1 /* xfrm4_tunnel.c: Generic IP tunnel transformer. 2 * 3 * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4 */ 5 6 #include <linux/skbuff.h> 7 #include <linux/module.h> 8 #include <net/xfrm.h> 9 #include <net/ip.h> 10 #include <net/protocol.h> 11 12 static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) 13 { 14 struct iphdr *iph; 15 16 iph = skb->nh.iph; 17 iph->tot_len = htons(skb->len); 18 ip_send_check(iph); 19 20 return 0; 21 } 22 23 static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) 24 { 25 return 0; 26 } 27 28 static struct xfrm_tunnel *ipip_handler; 29 static DECLARE_MUTEX(xfrm4_tunnel_sem); 30 31 int xfrm4_tunnel_register(struct xfrm_tunnel *handler) 32 { 33 int ret; 34 35 down(&xfrm4_tunnel_sem); 36 ret = 0; 37 if (ipip_handler != NULL) 38 ret = -EINVAL; 39 if (!ret) 40 ipip_handler = handler; 41 up(&xfrm4_tunnel_sem); 42 43 return ret; 44 } 45 46 EXPORT_SYMBOL(xfrm4_tunnel_register); 47 48 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) 49 { 50 int ret; 51 52 down(&xfrm4_tunnel_sem); 53 ret = 0; 54 if (ipip_handler != handler) 55 ret = -EINVAL; 56 if (!ret) 57 ipip_handler = NULL; 58 up(&xfrm4_tunnel_sem); 59 60 synchronize_net(); 61 62 return ret; 63 } 64 65 EXPORT_SYMBOL(xfrm4_tunnel_deregister); 66 67 static int ipip_rcv(struct sk_buff *skb) 68 { 69 struct xfrm_tunnel *handler = ipip_handler; 70 71 /* Tunnel devices take precedence. */ 72 if (handler && handler->handler(skb) == 0) 73 return 0; 74 75 return xfrm4_rcv(skb); 76 } 77 78 static void ipip_err(struct sk_buff *skb, u32 info) 79 { 80 struct xfrm_tunnel *handler = ipip_handler; 81 u32 arg = info; 82 83 if (handler) 84 handler->err_handler(skb, &arg); 85 } 86 87 static int ipip_init_state(struct xfrm_state *x, void *args) 88 { 89 if (!x->props.mode) 90 return -EINVAL; 91 92 if (x->encap) 93 return -EINVAL; 94 95 x->props.header_len = sizeof(struct iphdr); 96 97 return 0; 98 } 99 100 static void ipip_destroy(struct xfrm_state *x) 101 { 102 } 103 104 static struct xfrm_type ipip_type = { 105 .description = "IPIP", 106 .owner = THIS_MODULE, 107 .proto = IPPROTO_IPIP, 108 .init_state = ipip_init_state, 109 .destructor = ipip_destroy, 110 .input = ipip_xfrm_rcv, 111 .output = ipip_output 112 }; 113 114 static struct net_protocol ipip_protocol = { 115 .handler = ipip_rcv, 116 .err_handler = ipip_err, 117 .no_policy = 1, 118 }; 119 120 static int __init ipip_init(void) 121 { 122 if (xfrm_register_type(&ipip_type, AF_INET) < 0) { 123 printk(KERN_INFO "ipip init: can't add xfrm type\n"); 124 return -EAGAIN; 125 } 126 if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) { 127 printk(KERN_INFO "ipip init: can't add protocol\n"); 128 xfrm_unregister_type(&ipip_type, AF_INET); 129 return -EAGAIN; 130 } 131 return 0; 132 } 133 134 static void __exit ipip_fini(void) 135 { 136 if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) 137 printk(KERN_INFO "ipip close: can't remove protocol\n"); 138 if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) 139 printk(KERN_INFO "ipip close: can't remove xfrm type\n"); 140 } 141 142 module_init(ipip_init); 143 module_exit(ipip_fini); 144 MODULE_LICENSE("GPL"); 145