bb4033553f3b8c7fd6d5b2639129d1e236d6c278
[powerpc.git] / 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/module.h>
26 #include <linux/skbuff.h>
27 #include <linux/time.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
93         if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) ||
94             !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3)))
95                 return -1;
96
97         mh = (struct ip6_mh *)skb->h.raw;
98
99         if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) {
100                 LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n",
101                                mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type));
102                 mip6_param_prob(skb, 0, ((&mh->ip6mh_hdrlen) -
103                                          skb_network_header(skb)));
104                 return -1;
105         }
106
107         if (mh->ip6mh_proto != IPPROTO_NONE) {
108                 LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n",
109                                mh->ip6mh_proto);
110                 mip6_param_prob(skb, 0, ((&mh->ip6mh_proto) -
111                                          skb_network_header(skb)));
112                 return -1;
113         }
114
115         return 0;
116 }
117
118 struct mip6_report_rate_limiter {
119         spinlock_t lock;
120         struct timeval stamp;
121         int iif;
122         struct in6_addr src;
123         struct in6_addr dst;
124 };
125
126 static struct mip6_report_rate_limiter mip6_report_rl = {
127         .lock = SPIN_LOCK_UNLOCKED
128 };
129
130 static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
131 {
132         struct ipv6hdr *iph = skb->nh.ipv6h;
133         struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
134
135         if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
136             !ipv6_addr_any((struct in6_addr *)x->coaddr))
137                 return -ENOENT;
138
139         return destopt->nexthdr;
140 }
141
142 /* Destination Option Header is inserted.
143  * IP Header's src address is replaced with Home Address Option in
144  * Destination Option Header.
145  */
146 static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb)
147 {
148         struct ipv6hdr *iph;
149         struct ipv6_destopt_hdr *dstopt;
150         struct ipv6_destopt_hao *hao;
151         u8 nexthdr;
152         int len;
153
154         iph = (struct ipv6hdr *)skb->data;
155         iph->payload_len = htons(skb->len - sizeof(*iph));
156
157         nexthdr = *skb_network_header(skb);
158         *skb_network_header(skb) = IPPROTO_DSTOPTS;
159
160         dstopt = (struct ipv6_destopt_hdr *)skb->h.raw;
161         dstopt->nexthdr = nexthdr;
162
163         hao = mip6_padn((char *)(dstopt + 1),
164                         calc_padlen(sizeof(*dstopt), 6));
165
166         hao->type = IPV6_TLV_HAO;
167         hao->length = sizeof(*hao) - 2;
168         BUG_TRAP(hao->length == 16);
169
170         len = ((char *)hao - (char *)dstopt) + sizeof(*hao);
171
172         memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr));
173         memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
174
175         BUG_TRAP(len == x->props.header_len);
176         dstopt->hdrlen = (x->props.header_len >> 3) - 1;
177
178         return 0;
179 }
180
181 static inline int mip6_report_rl_allow(struct timeval *stamp,
182                                        struct in6_addr *dst,
183                                        struct in6_addr *src, int iif)
184 {
185         int allow = 0;
186
187         spin_lock_bh(&mip6_report_rl.lock);
188         if (mip6_report_rl.stamp.tv_sec != stamp->tv_sec ||
189             mip6_report_rl.stamp.tv_usec != stamp->tv_usec ||
190             mip6_report_rl.iif != iif ||
191             !ipv6_addr_equal(&mip6_report_rl.src, src) ||
192             !ipv6_addr_equal(&mip6_report_rl.dst, dst)) {
193                 mip6_report_rl.stamp.tv_sec = stamp->tv_sec;
194                 mip6_report_rl.stamp.tv_usec = stamp->tv_usec;
195                 mip6_report_rl.iif = iif;
196                 ipv6_addr_copy(&mip6_report_rl.src, src);
197                 ipv6_addr_copy(&mip6_report_rl.dst, dst);
198                 allow = 1;
199         }
200         spin_unlock_bh(&mip6_report_rl.lock);
201         return allow;
202 }
203
204 static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl)
205 {
206         struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
207         struct ipv6_destopt_hao *hao = NULL;
208         struct xfrm_selector sel;
209         int offset;
210         struct timeval stamp;
211         int err = 0;
212
213         if (unlikely(fl->proto == IPPROTO_MH &&
214                      fl->fl_mh_type <= IP6_MH_TYPE_MAX))
215                 goto out;
216
217         if (likely(opt->dsthao)) {
218                 offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO);
219                 if (likely(offset >= 0))
220                         hao = (struct ipv6_destopt_hao *)
221                                         (skb_network_header(skb) + offset);
222         }
223
224         skb_get_timestamp(skb, &stamp);
225
226         if (!mip6_report_rl_allow(&stamp, &skb->nh.ipv6h->daddr,
227                                   hao ? &hao->addr : &skb->nh.ipv6h->saddr,
228                                   opt->iif))
229                 goto out;
230
231         memset(&sel, 0, sizeof(sel));
232         memcpy(&sel.daddr, (xfrm_address_t *)&skb->nh.ipv6h->daddr,
233                sizeof(sel.daddr));
234         sel.prefixlen_d = 128;
235         memcpy(&sel.saddr, (xfrm_address_t *)&skb->nh.ipv6h->saddr,
236                sizeof(sel.saddr));
237         sel.prefixlen_s = 128;
238         sel.family = AF_INET6;
239         sel.proto = fl->proto;
240         sel.dport = xfrm_flowi_dport(fl);
241         if (sel.dport)
242                 sel.dport_mask = htons(~0);
243         sel.sport = xfrm_flowi_sport(fl);
244         if (sel.sport)
245                 sel.sport_mask = htons(~0);
246         sel.ifindex = fl->oif;
247
248         err = km_report(IPPROTO_DSTOPTS, &sel,
249                         (hao ? (xfrm_address_t *)&hao->addr : NULL));
250
251  out:
252         return err;
253 }
254
255 static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
256                                u8 **nexthdr)
257 {
258         u16 offset = sizeof(struct ipv6hdr);
259         struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
260         const unsigned char *nh = skb_network_header(skb);
261         unsigned int packet_len = skb->tail - nh;
262         int found_rhdr = 0;
263
264         *nexthdr = &skb->nh.ipv6h->nexthdr;
265
266         while (offset + 1 <= packet_len) {
267
268                 switch (**nexthdr) {
269                 case NEXTHDR_HOP:
270                         break;
271                 case NEXTHDR_ROUTING:
272                         found_rhdr = 1;
273                         break;
274                 case NEXTHDR_DEST:
275                         /*
276                          * HAO MUST NOT appear more than once.
277                          * XXX: It is better to try to find by the end of
278                          * XXX: packet if HAO exists.
279                          */
280                         if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) {
281                                 LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n");
282                                 return offset;
283                         }
284
285                         if (found_rhdr)
286                                 return offset;
287
288                         break;
289                 default:
290                         return offset;
291                 }
292
293                 offset += ipv6_optlen(exthdr);
294                 *nexthdr = &exthdr->nexthdr;
295                 exthdr = (struct ipv6_opt_hdr *)(nh + offset);
296         }
297
298         return offset;
299 }
300
301 static int mip6_destopt_init_state(struct xfrm_state *x)
302 {
303         if (x->id.spi) {
304                 printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
305                        x->id.spi);
306                 return -EINVAL;
307         }
308         if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
309                 printk(KERN_INFO "%s: state's mode is not %u: %u\n",
310                        __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
311                 return -EINVAL;
312         }
313
314         x->props.header_len = sizeof(struct ipv6_destopt_hdr) +
315                 calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) +
316                 sizeof(struct ipv6_destopt_hao);
317         BUG_TRAP(x->props.header_len == 24);
318
319         return 0;
320 }
321
322 /*
323  * Do nothing about destroying since it has no specific operation for
324  * destination options header unlike IPsec protocols.
325  */
326 static void mip6_destopt_destroy(struct xfrm_state *x)
327 {
328 }
329
330 static struct xfrm_type mip6_destopt_type =
331 {
332         .description    = "MIP6DESTOPT",
333         .owner          = THIS_MODULE,
334         .proto          = IPPROTO_DSTOPTS,
335         .flags          = XFRM_TYPE_NON_FRAGMENT,
336         .init_state     = mip6_destopt_init_state,
337         .destructor     = mip6_destopt_destroy,
338         .input          = mip6_destopt_input,
339         .output         = mip6_destopt_output,
340         .reject         = mip6_destopt_reject,
341         .hdr_offset     = mip6_destopt_offset,
342         .local_addr     = mip6_xfrm_addr,
343 };
344
345 static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
346 {
347         struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
348
349         if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) &&
350             !ipv6_addr_any((struct in6_addr *)x->coaddr))
351                 return -ENOENT;
352
353         return rt2->rt_hdr.nexthdr;
354 }
355
356 /* Routing Header type 2 is inserted.
357  * IP Header's dst address is replaced with Routing Header's Home Address.
358  */
359 static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
360 {
361         struct ipv6hdr *iph;
362         struct rt2_hdr *rt2;
363         u8 nexthdr;
364
365         iph = (struct ipv6hdr *)skb->data;
366         iph->payload_len = htons(skb->len - sizeof(*iph));
367
368         nexthdr = *skb_network_header(skb);
369         *skb_network_header(skb) = IPPROTO_ROUTING;
370
371         rt2 = (struct rt2_hdr *)skb->h.raw;
372         rt2->rt_hdr.nexthdr = nexthdr;
373         rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
374         rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
375         rt2->rt_hdr.segments_left = 1;
376         memset(&rt2->reserved, 0, sizeof(rt2->reserved));
377
378         BUG_TRAP(rt2->rt_hdr.hdrlen == 2);
379
380         memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr));
381         memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
382
383         return 0;
384 }
385
386 static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
387                              u8 **nexthdr)
388 {
389         u16 offset = sizeof(struct ipv6hdr);
390         struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
391         const unsigned char *nh = skb_network_header(skb);
392         unsigned int packet_len = skb->tail - nh;
393         int found_rhdr = 0;
394
395         *nexthdr = &skb->nh.ipv6h->nexthdr;
396
397         while (offset + 1 <= packet_len) {
398
399                 switch (**nexthdr) {
400                 case NEXTHDR_HOP:
401                         break;
402                 case NEXTHDR_ROUTING:
403                         if (offset + 3 <= packet_len) {
404                                 struct ipv6_rt_hdr *rt;
405                                 rt = (struct ipv6_rt_hdr *)(nh + offset);
406                                 if (rt->type != 0)
407                                         return offset;
408                         }
409                         found_rhdr = 1;
410                         break;
411                 case NEXTHDR_DEST:
412                         if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
413                                 return offset;
414
415                         if (found_rhdr)
416                                 return offset;
417
418                         break;
419                 default:
420                         return offset;
421                 }
422
423                 offset += ipv6_optlen(exthdr);
424                 *nexthdr = &exthdr->nexthdr;
425                 exthdr = (struct ipv6_opt_hdr *)(nh + offset);
426         }
427
428         return offset;
429 }
430
431 static int mip6_rthdr_init_state(struct xfrm_state *x)
432 {
433         if (x->id.spi) {
434                 printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
435                        x->id.spi);
436                 return -EINVAL;
437         }
438         if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
439                 printk(KERN_INFO "%s: state's mode is not %u: %u\n",
440                        __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
441                 return -EINVAL;
442         }
443
444         x->props.header_len = sizeof(struct rt2_hdr);
445
446         return 0;
447 }
448
449 /*
450  * Do nothing about destroying since it has no specific operation for routing
451  * header type 2 unlike IPsec protocols.
452  */
453 static void mip6_rthdr_destroy(struct xfrm_state *x)
454 {
455 }
456
457 static struct xfrm_type mip6_rthdr_type =
458 {
459         .description    = "MIP6RT",
460         .owner          = THIS_MODULE,
461         .proto          = IPPROTO_ROUTING,
462         .flags          = XFRM_TYPE_NON_FRAGMENT,
463         .init_state     = mip6_rthdr_init_state,
464         .destructor     = mip6_rthdr_destroy,
465         .input          = mip6_rthdr_input,
466         .output         = mip6_rthdr_output,
467         .hdr_offset     = mip6_rthdr_offset,
468         .remote_addr    = mip6_xfrm_addr,
469 };
470
471 int __init mip6_init(void)
472 {
473         printk(KERN_INFO "Mobile IPv6\n");
474
475         if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
476                 printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__);
477                 goto mip6_destopt_xfrm_fail;
478         }
479         if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
480                 printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__);
481                 goto mip6_rthdr_xfrm_fail;
482         }
483         return 0;
484
485  mip6_rthdr_xfrm_fail:
486         xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
487  mip6_destopt_xfrm_fail:
488         return -EAGAIN;
489 }
490
491 void __exit mip6_fini(void)
492 {
493         if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
494                 printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__);
495         if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
496                 printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__);
497 }