[IPV6] MIP6: Add receiving mobility header functions through raw socket.
[linux-2.6] / net / ipv6 / mip6.c
1 /*
2  * Copyright (C)2003-2006 Helsinki University of Technology
3  * Copyright (C)2003-2006 USAGI/WIDE Project
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 /*
20  * Authors:
21  *      Noriaki TAKAMIYA @USAGI
22  *      Masahide NAKAMURA @USAGI
23  */
24
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/skbuff.h>
28 #include <linux/ipv6.h>
29 #include <linux/icmpv6.h>
30 #include <net/sock.h>
31 #include <net/ipv6.h>
32 #include <net/ip6_checksum.h>
33 #include <net/xfrm.h>
34 #include <net/mip6.h>
35
36 static xfrm_address_t *mip6_xfrm_addr(struct xfrm_state *x, xfrm_address_t *addr)
37 {
38         return x->coaddr;
39 }
40
41 static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
42 {
43         return (n - len + 16) & 0x7;
44 }
45
46 static inline void *mip6_padn(__u8 *data, __u8 padlen)
47 {
48         if (!data)
49                 return NULL;
50         if (padlen == 1) {
51                 data[0] = MIP6_OPT_PAD_1;
52         } else if (padlen > 1) {
53                 data[0] = MIP6_OPT_PAD_N;
54                 data[1] = padlen - 2;
55                 if (padlen > 2)
56                         memset(data+2, 0, data[1]);
57         }
58         return data + padlen;
59 }
60
61 static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos)
62 {
63         icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
64 }
65
66 static int mip6_mh_len(int type)
67 {
68         int len = 0;
69
70         switch (type) {
71         case IP6_MH_TYPE_BRR:
72                 len = 0;
73                 break;
74         case IP6_MH_TYPE_HOTI:
75         case IP6_MH_TYPE_COTI:
76         case IP6_MH_TYPE_BU:
77         case IP6_MH_TYPE_BACK:
78                 len = 1;
79                 break;
80         case IP6_MH_TYPE_HOT:
81         case IP6_MH_TYPE_COT:
82         case IP6_MH_TYPE_BERROR:
83                 len = 2;
84                 break;
85         }
86         return len;
87 }
88
89 int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
90 {
91         struct ip6_mh *mh;
92         int mhlen;
93
94         if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) ||
95             !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3)))
96                 return -1;
97
98         mh = (struct ip6_mh *)skb->h.raw;
99
100         if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
101                 LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n",
102                                mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type));
103                 mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw);
104                 return -1;
105         }
106         mhlen = (mh->ip6mh_hdrlen + 1) << 3;
107
108         if (skb->ip_summed == CHECKSUM_COMPLETE) {
109                 skb->ip_summed = CHECKSUM_UNNECESSARY;
110                 if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
111                                     &skb->nh.ipv6h->daddr,
112                                     mhlen, IPPROTO_MH,
113                                     skb->csum)) {
114                         LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n");
115                         skb->ip_summed = CHECKSUM_NONE;
116                 }
117         }
118         if (skb->ip_summed == CHECKSUM_NONE) {
119                 if (csum_ipv6_magic(&skb->nh.ipv6h->saddr,
120                                     &skb->nh.ipv6h->daddr,
121                                     mhlen, IPPROTO_MH,
122                                     skb_checksum(skb, 0, mhlen, 0))) {
123                         LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
124                                        NIP6(skb->nh.ipv6h->saddr),
125                                        NIP6(skb->nh.ipv6h->daddr));
126                         return -1;
127                 }
128                 skb->ip_summed = CHECKSUM_UNNECESSARY;
129         }
130
131         if (mh->ip6mh_proto != IPPROTO_NONE) {
132                 LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
133                                mh->ip6mh_proto);
134                 mip6_param_prob(skb, 0, (&mh->ip6mh_proto) - skb->nh.raw);
135                 return -1;
136         }
137
138         return 0;
139 }
140
141 static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
142 {
143         struct ipv6hdr *iph = skb->nh.ipv6h;
144         struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
145
146         if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
147             !ipv6_addr_any((struct in6_addr *)x->coaddr))
148                 return -ENOENT;
149
150         return destopt->nexthdr;
151 }
152
153 /* Destination Option Header is inserted.
154  * IP Header's src address is replaced with Home Address Option in
155  * Destination Option Header.
156  */
157 static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
158 {
159         struct ipv6hdr *iph;
160         struct ipv6_destopt_hdr *dstopt;
161         struct ipv6_destopt_hao *hao;
162         u8 nexthdr;
163         int len;
164
165         iph = (struct ipv6hdr *)skb->data;
166         iph->payload_len = htons(skb->len - sizeof(*iph));
167
168         nexthdr = *skb->nh.raw;
169         *skb->nh.raw = IPPROTO_DSTOPTS;
170
171         dstopt = (struct ipv6_destopt_hdr *)skb->h.raw;
172         dstopt->nexthdr = nexthdr;
173
174         hao = mip6_padn((char *)(dstopt + 1),
175                         calc_padlen(sizeof(*dstopt), 6));
176
177         hao->type = IPV6_TLV_HAO;
178         hao->length = sizeof(*hao) - 2;
179         BUG_TRAP(hao->length == 16);
180
181         len = ((char *)hao - (char *)dstopt) + sizeof(*hao);
182
183         memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr));
184         memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
185
186         BUG_TRAP(len == x->props.header_len);
187         dstopt->hdrlen = (x->props.header_len >> 3) - 1;
188
189         return 0;
190 }
191
192 static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
193                                u8 **nexthdr)
194 {
195         u16 offset = sizeof(struct ipv6hdr);
196         struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
197         unsigned int packet_len = skb->tail - skb->nh.raw;
198         int found_rhdr = 0;
199
200         *nexthdr = &skb->nh.ipv6h->nexthdr;
201
202         while (offset + 1 <= packet_len) {
203
204                 switch (**nexthdr) {
205                 case NEXTHDR_HOP:
206                         break;
207                 case NEXTHDR_ROUTING:
208                         found_rhdr = 1;
209                         break;
210                 case NEXTHDR_DEST:
211                         /*
212                          * HAO MUST NOT appear more than once.
213                          * XXX: It is better to try to find by the end of
214                          * XXX: packet if HAO exists.
215                          */
216                         if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
217                                 LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n");
218                                 return offset;
219                         }
220
221                         if (found_rhdr)
222                                 return offset;
223
224                         break;
225                 default:
226                         return offset;
227                 }
228
229                 offset += ipv6_optlen(exthdr);
230                 *nexthdr = &exthdr->nexthdr;
231                 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
232         }
233
234         return offset;
235 }
236
237 static int mip6_destopt_init_state(struct xfrm_state *x)
238 {
239         if (x->id.spi) {
240                 printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
241                        x->id.spi);
242                 return -EINVAL;
243         }
244         if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
245                 printk(KERN_INFO "%s: state's mode is not %u: %u\n",
246                        __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
247                 return -EINVAL;
248         }
249
250         x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
251                 calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
252                 sizeof(struct ipv6_destopt_hao);
253         BUG_TRAP(x->props.header_len == 24);
254
255         return 0;
256 }
257
258 /*
259  * Do nothing about destroying since it has no specific operation for
260  * destination options header unlike IPsec protocols.
261  */
262 static void mip6_destopt_destroy(struct xfrm_state *x)
263 {
264 }
265
266 static struct xfrm_type mip6_destopt_type =
267 {
268         .description    = "MIP6DESTOPT",
269         .owner          = THIS_MODULE,
270         .proto          = IPPROTO_DSTOPTS,
271         .flags          = XFRM_TYPE_NON_FRAGMENT,
272         .init_state     = mip6_destopt_init_state,
273         .destructor     = mip6_destopt_destroy,
274         .input          = mip6_destopt_input,
275         .output         = mip6_destopt_output,
276         .hdr_offset     = mip6_destopt_offset,
277         .local_addr     = mip6_xfrm_addr,
278 };
279
280 static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
281 {
282         struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
283
284         if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) &&
285             !ipv6_addr_any((struct in6_addr *)x->coaddr))
286                 return -ENOENT;
287
288         return rt2->rt_hdr.nexthdr;
289 }
290
291 /* Routing Header type 2 is inserted.
292  * IP Header's dst address is replaced with Routing Header's Home Address.
293  */
294 static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
295 {
296         struct ipv6hdr *iph;
297         struct rt2_hdr *rt2;
298         u8 nexthdr;
299
300         iph = (struct ipv6hdr *)skb->data;
301         iph->payload_len = htons(skb->len - sizeof(*iph));
302
303         nexthdr = *skb->nh.raw;
304         *skb->nh.raw = IPPROTO_ROUTING;
305
306         rt2 = (struct rt2_hdr *)skb->h.raw;
307         rt2->rt_hdr.nexthdr = nexthdr;
308         rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
309         rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
310         rt2->rt_hdr.segments_left = 1;
311         memset(&rt2->reserved, 0, sizeof(rt2->reserved));
312
313         BUG_TRAP(rt2->rt_hdr.hdrlen == 2);
314
315         memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
316         memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
317
318         return 0;
319 }
320
321 static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
322                              u8 **nexthdr)
323 {
324         u16 offset = sizeof(struct ipv6hdr);
325         struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
326         unsigned int packet_len = skb->tail - skb->nh.raw;
327         int found_rhdr = 0;
328
329         *nexthdr = &skb->nh.ipv6h->nexthdr;
330
331         while (offset + 1 <= packet_len) {
332
333                 switch (**nexthdr) {
334                 case NEXTHDR_HOP:
335                         break;
336                 case NEXTHDR_ROUTING:
337                         if (offset + 3 <= packet_len) {
338                                 struct ipv6_rt_hdr *rt;
339                                 rt = (struct ipv6_rt_hdr *)(skb->nh.raw + offset);
340                                 if (rt->type != 0)
341                                         return offset;
342                         }
343                         found_rhdr = 1;
344                         break;
345                 case NEXTHDR_DEST:
346                         if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
347                                 return offset;
348
349                         if (found_rhdr)
350                                 return offset;
351
352                         break;
353                 default:
354                         return offset;
355                 }
356
357                 offset += ipv6_optlen(exthdr);
358                 *nexthdr = &exthdr->nexthdr;
359                 exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
360         }
361
362         return offset;
363 }
364
365 static int mip6_rthdr_init_state(struct xfrm_state *x)
366 {
367         if (x->id.spi) {
368                 printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
369                        x->id.spi);
370                 return -EINVAL;
371         }
372         if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
373                 printk(KERN_INFO "%s: state's mode is not %u: %u\n",
374                        __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
375                 return -EINVAL;
376         }
377
378         x->props.header_len = sizeof(struct rt2_hdr);
379
380         return 0;
381 }
382
383 /*
384  * Do nothing about destroying since it has no specific operation for routing
385  * header type 2 unlike IPsec protocols.
386  */
387 static void mip6_rthdr_destroy(struct xfrm_state *x)
388 {
389 }
390
391 static struct xfrm_type mip6_rthdr_type =
392 {
393         .description    = "MIP6RT",
394         .owner          = THIS_MODULE,
395         .proto          = IPPROTO_ROUTING,
396         .flags          = XFRM_TYPE_NON_FRAGMENT,
397         .init_state     = mip6_rthdr_init_state,
398         .destructor     = mip6_rthdr_destroy,
399         .input          = mip6_rthdr_input,
400         .output         = mip6_rthdr_output,
401         .hdr_offset     = mip6_rthdr_offset,
402         .remote_addr    = mip6_xfrm_addr,
403 };
404
405 int __init mip6_init(void)
406 {
407         printk(KERN_INFO "Mobile IPv6\n");
408
409         if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
410                 printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__);
411                 goto mip6_destopt_xfrm_fail;
412         }
413         if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
414                 printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__);
415                 goto mip6_rthdr_xfrm_fail;
416         }
417         return 0;
418
419  mip6_rthdr_xfrm_fail:
420         xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
421  mip6_destopt_xfrm_fail:
422         return -EAGAIN;
423 }
424
425 void __exit mip6_fini(void)
426 {
427         if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
428                 printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__);
429         if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
430                 printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__);
431 }