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