1d2acc347SHerbert Xu /* tunnel4.c: Generic IP tunnel transformer. 2d2acc347SHerbert Xu * 3d2acc347SHerbert Xu * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4d2acc347SHerbert Xu */ 5d2acc347SHerbert Xu 6d2acc347SHerbert Xu #include <linux/init.h> 7d2acc347SHerbert Xu #include <linux/module.h> 8d2acc347SHerbert Xu #include <linux/mutex.h> 9d2acc347SHerbert Xu #include <linux/netdevice.h> 10d2acc347SHerbert Xu #include <linux/skbuff.h> 1150fba2aaSHerbert Xu #include <net/icmp.h> 1250fba2aaSHerbert Xu #include <net/ip.h> 13d2acc347SHerbert Xu #include <net/protocol.h> 14d2acc347SHerbert Xu #include <net/xfrm.h> 15d2acc347SHerbert Xu 16d2acc347SHerbert Xu static struct xfrm_tunnel *tunnel4_handlers; 17*c0d56408SKazunori MIYAZAWA static struct xfrm_tunnel *tunnel64_handlers; 18d2acc347SHerbert Xu static DEFINE_MUTEX(tunnel4_mutex); 19d2acc347SHerbert Xu 20*c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 21d2acc347SHerbert Xu { 22d2acc347SHerbert Xu struct xfrm_tunnel **pprev; 23d2acc347SHerbert Xu int ret = -EEXIST; 24d2acc347SHerbert Xu int priority = handler->priority; 25d2acc347SHerbert Xu 26d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 27d2acc347SHerbert Xu 28*c0d56408SKazunori MIYAZAWA for (pprev = (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 29*c0d56408SKazunori MIYAZAWA *pprev; pprev = &(*pprev)->next) { 30d2acc347SHerbert Xu if ((*pprev)->priority > priority) 31d2acc347SHerbert Xu break; 32d2acc347SHerbert Xu if ((*pprev)->priority == priority) 33d2acc347SHerbert Xu goto err; 34d2acc347SHerbert Xu } 35d2acc347SHerbert Xu 36d2acc347SHerbert Xu handler->next = *pprev; 37d2acc347SHerbert Xu *pprev = handler; 38d2acc347SHerbert Xu 39d2acc347SHerbert Xu ret = 0; 40d2acc347SHerbert Xu 41d2acc347SHerbert Xu err: 42d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 43d2acc347SHerbert Xu 44d2acc347SHerbert Xu return ret; 45d2acc347SHerbert Xu } 46d2acc347SHerbert Xu 47d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_register); 48d2acc347SHerbert Xu 49*c0d56408SKazunori MIYAZAWA int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) 50d2acc347SHerbert Xu { 51d2acc347SHerbert Xu struct xfrm_tunnel **pprev; 52d2acc347SHerbert Xu int ret = -ENOENT; 53d2acc347SHerbert Xu 54d2acc347SHerbert Xu mutex_lock(&tunnel4_mutex); 55d2acc347SHerbert Xu 56*c0d56408SKazunori MIYAZAWA for (pprev = (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 57*c0d56408SKazunori MIYAZAWA *pprev; pprev = &(*pprev)->next) { 58d2acc347SHerbert Xu if (*pprev == handler) { 59d2acc347SHerbert Xu *pprev = handler->next; 60d2acc347SHerbert Xu ret = 0; 61d2acc347SHerbert Xu break; 62d2acc347SHerbert Xu } 63d2acc347SHerbert Xu } 64d2acc347SHerbert Xu 65d2acc347SHerbert Xu mutex_unlock(&tunnel4_mutex); 66d2acc347SHerbert Xu 67d2acc347SHerbert Xu synchronize_net(); 68d2acc347SHerbert Xu 69d2acc347SHerbert Xu return ret; 70d2acc347SHerbert Xu } 71d2acc347SHerbert Xu 72d2acc347SHerbert Xu EXPORT_SYMBOL(xfrm4_tunnel_deregister); 73d2acc347SHerbert Xu 74d2acc347SHerbert Xu static int tunnel4_rcv(struct sk_buff *skb) 75d2acc347SHerbert Xu { 76d2acc347SHerbert Xu struct xfrm_tunnel *handler; 77d2acc347SHerbert Xu 7850fba2aaSHerbert Xu if (!pskb_may_pull(skb, sizeof(struct iphdr))) 7950fba2aaSHerbert Xu goto drop; 8050fba2aaSHerbert Xu 81d2acc347SHerbert Xu for (handler = tunnel4_handlers; handler; handler = handler->next) 82d2acc347SHerbert Xu if (!handler->handler(skb)) 83d2acc347SHerbert Xu return 0; 84d2acc347SHerbert Xu 8550fba2aaSHerbert Xu icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 8650fba2aaSHerbert Xu 8750fba2aaSHerbert Xu drop: 88d2acc347SHerbert Xu kfree_skb(skb); 89d2acc347SHerbert Xu return 0; 90d2acc347SHerbert Xu } 91d2acc347SHerbert Xu 92*c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 93*c0d56408SKazunori MIYAZAWA static int tunnel64_rcv(struct sk_buff *skb) 94*c0d56408SKazunori MIYAZAWA { 95*c0d56408SKazunori MIYAZAWA struct xfrm_tunnel *handler; 96*c0d56408SKazunori MIYAZAWA 97*c0d56408SKazunori MIYAZAWA if (!pskb_may_pull(skb, sizeof(struct iphdr))) 98*c0d56408SKazunori MIYAZAWA goto drop; 99*c0d56408SKazunori MIYAZAWA 100*c0d56408SKazunori MIYAZAWA for (handler = tunnel64_handlers; handler; handler = handler->next) 101*c0d56408SKazunori MIYAZAWA if (!handler->handler(skb)) 102*c0d56408SKazunori MIYAZAWA return 0; 103*c0d56408SKazunori MIYAZAWA 104*c0d56408SKazunori MIYAZAWA icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 105*c0d56408SKazunori MIYAZAWA 106*c0d56408SKazunori MIYAZAWA drop: 107*c0d56408SKazunori MIYAZAWA kfree_skb(skb); 108*c0d56408SKazunori MIYAZAWA return 0; 109*c0d56408SKazunori MIYAZAWA } 110*c0d56408SKazunori MIYAZAWA #endif 111*c0d56408SKazunori MIYAZAWA 112d2acc347SHerbert Xu static void tunnel4_err(struct sk_buff *skb, u32 info) 113d2acc347SHerbert Xu { 114d2acc347SHerbert Xu struct xfrm_tunnel *handler; 115d2acc347SHerbert Xu 116d2acc347SHerbert Xu for (handler = tunnel4_handlers; handler; handler = handler->next) 117d2acc347SHerbert Xu if (!handler->err_handler(skb, info)) 118d2acc347SHerbert Xu break; 119d2acc347SHerbert Xu } 120d2acc347SHerbert Xu 121d2acc347SHerbert Xu static struct net_protocol tunnel4_protocol = { 122d2acc347SHerbert Xu .handler = tunnel4_rcv, 123d2acc347SHerbert Xu .err_handler = tunnel4_err, 124d2acc347SHerbert Xu .no_policy = 1, 125d2acc347SHerbert Xu }; 126d2acc347SHerbert Xu 127*c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 128*c0d56408SKazunori MIYAZAWA static struct net_protocol tunnel64_protocol = { 129*c0d56408SKazunori MIYAZAWA .handler = tunnel64_rcv, 130*c0d56408SKazunori MIYAZAWA .err_handler = tunnel4_err, 131*c0d56408SKazunori MIYAZAWA .no_policy = 1, 132*c0d56408SKazunori MIYAZAWA }; 133*c0d56408SKazunori MIYAZAWA #endif 134*c0d56408SKazunori MIYAZAWA 135d2acc347SHerbert Xu static int __init tunnel4_init(void) 136d2acc347SHerbert Xu { 137d2acc347SHerbert Xu if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 138d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 init: can't add protocol\n"); 139d2acc347SHerbert Xu return -EAGAIN; 140d2acc347SHerbert Xu } 141*c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 142*c0d56408SKazunori MIYAZAWA if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 143*c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 init: can't add protocol\n"); 144*c0d56408SKazunori MIYAZAWA inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 145*c0d56408SKazunori MIYAZAWA return -EAGAIN; 146*c0d56408SKazunori MIYAZAWA } 147*c0d56408SKazunori MIYAZAWA #endif 148d2acc347SHerbert Xu return 0; 149d2acc347SHerbert Xu } 150d2acc347SHerbert Xu 151d2acc347SHerbert Xu static void __exit tunnel4_fini(void) 152d2acc347SHerbert Xu { 153*c0d56408SKazunori MIYAZAWA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 154*c0d56408SKazunori MIYAZAWA if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 155*c0d56408SKazunori MIYAZAWA printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); 156*c0d56408SKazunori MIYAZAWA #endif 157d2acc347SHerbert Xu if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) 158d2acc347SHerbert Xu printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); 159d2acc347SHerbert Xu } 160d2acc347SHerbert Xu 161d2acc347SHerbert Xu module_init(tunnel4_init); 162d2acc347SHerbert Xu module_exit(tunnel4_fini); 163d2acc347SHerbert Xu MODULE_LICENSE("GPL"); 164