xref: /openbmc/linux/net/ipv4/xfrm4_tunnel.c (revision 4a3e2f71)
11da177e4SLinus Torvalds /* xfrm4_tunnel.c: Generic IP tunnel transformer.
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <linux/skbuff.h>
71da177e4SLinus Torvalds #include <linux/module.h>
84a3e2f71SArjan van de Ven #include <linux/mutex.h>
91da177e4SLinus Torvalds #include <net/xfrm.h>
101da177e4SLinus Torvalds #include <net/ip.h>
111da177e4SLinus Torvalds #include <net/protocol.h>
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
141da177e4SLinus Torvalds {
151da177e4SLinus Torvalds 	struct iphdr *iph;
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds 	iph = skb->nh.iph;
181da177e4SLinus Torvalds 	iph->tot_len = htons(skb->len);
191da177e4SLinus Torvalds 	ip_send_check(iph);
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds 	return 0;
221da177e4SLinus Torvalds }
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds 	return 0;
271da177e4SLinus Torvalds }
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds static struct xfrm_tunnel *ipip_handler;
304a3e2f71SArjan van de Ven static DEFINE_MUTEX(xfrm4_tunnel_mutex);
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds 	int ret;
351da177e4SLinus Torvalds 
364a3e2f71SArjan van de Ven 	mutex_lock(&xfrm4_tunnel_mutex);
371da177e4SLinus Torvalds 	ret = 0;
381da177e4SLinus Torvalds 	if (ipip_handler != NULL)
391da177e4SLinus Torvalds 		ret = -EINVAL;
401da177e4SLinus Torvalds 	if (!ret)
411da177e4SLinus Torvalds 		ipip_handler = handler;
424a3e2f71SArjan van de Ven 	mutex_unlock(&xfrm4_tunnel_mutex);
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds 	return ret;
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm4_tunnel_register);
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
501da177e4SLinus Torvalds {
511da177e4SLinus Torvalds 	int ret;
521da177e4SLinus Torvalds 
534a3e2f71SArjan van de Ven 	mutex_lock(&xfrm4_tunnel_mutex);
541da177e4SLinus Torvalds 	ret = 0;
551da177e4SLinus Torvalds 	if (ipip_handler != handler)
561da177e4SLinus Torvalds 		ret = -EINVAL;
571da177e4SLinus Torvalds 	if (!ret)
581da177e4SLinus Torvalds 		ipip_handler = NULL;
594a3e2f71SArjan van de Ven 	mutex_unlock(&xfrm4_tunnel_mutex);
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	synchronize_net();
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	return ret;
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm4_tunnel_deregister);
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds static int ipip_rcv(struct sk_buff *skb)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	struct xfrm_tunnel *handler = ipip_handler;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	/* Tunnel devices take precedence.  */
731da177e4SLinus Torvalds 	if (handler && handler->handler(skb) == 0)
741da177e4SLinus Torvalds 		return 0;
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	return xfrm4_rcv(skb);
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds static void ipip_err(struct sk_buff *skb, u32 info)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	struct xfrm_tunnel *handler = ipip_handler;
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds 	if (handler)
840303770dSPatrick McHardy 		handler->err_handler(skb, info);
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds 
8772cb6962SHerbert Xu static int ipip_init_state(struct xfrm_state *x)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds 	if (!x->props.mode)
901da177e4SLinus Torvalds 		return -EINVAL;
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	if (x->encap)
931da177e4SLinus Torvalds 		return -EINVAL;
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds 	x->props.header_len = sizeof(struct iphdr);
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	return 0;
981da177e4SLinus Torvalds }
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds static void ipip_destroy(struct xfrm_state *x)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds static struct xfrm_type ipip_type = {
1051da177e4SLinus Torvalds 	.description	= "IPIP",
1061da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
1071da177e4SLinus Torvalds 	.proto	     	= IPPROTO_IPIP,
1081da177e4SLinus Torvalds 	.init_state	= ipip_init_state,
1091da177e4SLinus Torvalds 	.destructor	= ipip_destroy,
1101da177e4SLinus Torvalds 	.input		= ipip_xfrm_rcv,
1111da177e4SLinus Torvalds 	.output		= ipip_output
1121da177e4SLinus Torvalds };
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds static struct net_protocol ipip_protocol = {
1151da177e4SLinus Torvalds 	.handler	=	ipip_rcv,
1161da177e4SLinus Torvalds 	.err_handler	=	ipip_err,
1171da177e4SLinus Torvalds 	.no_policy	=	1,
1181da177e4SLinus Torvalds };
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds static int __init ipip_init(void)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	if (xfrm_register_type(&ipip_type, AF_INET) < 0) {
1231da177e4SLinus Torvalds 		printk(KERN_INFO "ipip init: can't add xfrm type\n");
1241da177e4SLinus Torvalds 		return -EAGAIN;
1251da177e4SLinus Torvalds 	}
1261da177e4SLinus Torvalds 	if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) {
1271da177e4SLinus Torvalds 		printk(KERN_INFO "ipip init: can't add protocol\n");
1281da177e4SLinus Torvalds 		xfrm_unregister_type(&ipip_type, AF_INET);
1291da177e4SLinus Torvalds 		return -EAGAIN;
1301da177e4SLinus Torvalds 	}
1311da177e4SLinus Torvalds 	return 0;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds static void __exit ipip_fini(void)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds 	if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0)
1371da177e4SLinus Torvalds 		printk(KERN_INFO "ipip close: can't remove protocol\n");
1381da177e4SLinus Torvalds 	if (xfrm_unregister_type(&ipip_type, AF_INET) < 0)
1391da177e4SLinus Torvalds 		printk(KERN_INFO "ipip close: can't remove xfrm type\n");
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds module_init(ipip_init);
1431da177e4SLinus Torvalds module_exit(ipip_fini);
1441da177e4SLinus Torvalds MODULE_LICENSE("GPL");
145