xref: /openbmc/linux/net/ipv4/xfrm4_tunnel.c (revision 0303770d)
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>
81da177e4SLinus Torvalds #include <net/xfrm.h>
91da177e4SLinus Torvalds #include <net/ip.h>
101da177e4SLinus Torvalds #include <net/protocol.h>
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
131da177e4SLinus Torvalds {
141da177e4SLinus Torvalds 	struct iphdr *iph;
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds 	iph = skb->nh.iph;
171da177e4SLinus Torvalds 	iph->tot_len = htons(skb->len);
181da177e4SLinus Torvalds 	ip_send_check(iph);
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds 	return 0;
211da177e4SLinus Torvalds }
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
241da177e4SLinus Torvalds {
251da177e4SLinus Torvalds 	return 0;
261da177e4SLinus Torvalds }
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds static struct xfrm_tunnel *ipip_handler;
291da177e4SLinus Torvalds static DECLARE_MUTEX(xfrm4_tunnel_sem);
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
321da177e4SLinus Torvalds {
331da177e4SLinus Torvalds 	int ret;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	down(&xfrm4_tunnel_sem);
361da177e4SLinus Torvalds 	ret = 0;
371da177e4SLinus Torvalds 	if (ipip_handler != NULL)
381da177e4SLinus Torvalds 		ret = -EINVAL;
391da177e4SLinus Torvalds 	if (!ret)
401da177e4SLinus Torvalds 		ipip_handler = handler;
411da177e4SLinus Torvalds 	up(&xfrm4_tunnel_sem);
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	return ret;
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm4_tunnel_register);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	int ret;
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	down(&xfrm4_tunnel_sem);
531da177e4SLinus Torvalds 	ret = 0;
541da177e4SLinus Torvalds 	if (ipip_handler != handler)
551da177e4SLinus Torvalds 		ret = -EINVAL;
561da177e4SLinus Torvalds 	if (!ret)
571da177e4SLinus Torvalds 		ipip_handler = NULL;
581da177e4SLinus Torvalds 	up(&xfrm4_tunnel_sem);
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	synchronize_net();
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	return ret;
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm4_tunnel_deregister);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds static int ipip_rcv(struct sk_buff *skb)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	struct xfrm_tunnel *handler = ipip_handler;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	/* Tunnel devices take precedence.  */
721da177e4SLinus Torvalds 	if (handler && handler->handler(skb) == 0)
731da177e4SLinus Torvalds 		return 0;
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds 	return xfrm4_rcv(skb);
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds static void ipip_err(struct sk_buff *skb, u32 info)
791da177e4SLinus Torvalds {
801da177e4SLinus Torvalds 	struct xfrm_tunnel *handler = ipip_handler;
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	if (handler)
830303770dSPatrick McHardy 		handler->err_handler(skb, info);
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds 
8672cb6962SHerbert Xu static int ipip_init_state(struct xfrm_state *x)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds 	if (!x->props.mode)
891da177e4SLinus Torvalds 		return -EINVAL;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	if (x->encap)
921da177e4SLinus Torvalds 		return -EINVAL;
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	x->props.header_len = sizeof(struct iphdr);
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	return 0;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds static void ipip_destroy(struct xfrm_state *x)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds static struct xfrm_type ipip_type = {
1041da177e4SLinus Torvalds 	.description	= "IPIP",
1051da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
1061da177e4SLinus Torvalds 	.proto	     	= IPPROTO_IPIP,
1071da177e4SLinus Torvalds 	.init_state	= ipip_init_state,
1081da177e4SLinus Torvalds 	.destructor	= ipip_destroy,
1091da177e4SLinus Torvalds 	.input		= ipip_xfrm_rcv,
1101da177e4SLinus Torvalds 	.output		= ipip_output
1111da177e4SLinus Torvalds };
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds static struct net_protocol ipip_protocol = {
1141da177e4SLinus Torvalds 	.handler	=	ipip_rcv,
1151da177e4SLinus Torvalds 	.err_handler	=	ipip_err,
1161da177e4SLinus Torvalds 	.no_policy	=	1,
1171da177e4SLinus Torvalds };
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds static int __init ipip_init(void)
1201da177e4SLinus Torvalds {
1211da177e4SLinus Torvalds 	if (xfrm_register_type(&ipip_type, AF_INET) < 0) {
1221da177e4SLinus Torvalds 		printk(KERN_INFO "ipip init: can't add xfrm type\n");
1231da177e4SLinus Torvalds 		return -EAGAIN;
1241da177e4SLinus Torvalds 	}
1251da177e4SLinus Torvalds 	if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) {
1261da177e4SLinus Torvalds 		printk(KERN_INFO "ipip init: can't add protocol\n");
1271da177e4SLinus Torvalds 		xfrm_unregister_type(&ipip_type, AF_INET);
1281da177e4SLinus Torvalds 		return -EAGAIN;
1291da177e4SLinus Torvalds 	}
1301da177e4SLinus Torvalds 	return 0;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds static void __exit ipip_fini(void)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0)
1361da177e4SLinus Torvalds 		printk(KERN_INFO "ipip close: can't remove protocol\n");
1371da177e4SLinus Torvalds 	if (xfrm_unregister_type(&ipip_type, AF_INET) < 0)
1381da177e4SLinus Torvalds 		printk(KERN_INFO "ipip close: can't remove xfrm type\n");
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds module_init(ipip_init);
1421da177e4SLinus Torvalds module_exit(ipip_fini);
1431da177e4SLinus Torvalds MODULE_LICENSE("GPL");
144