blob: 084f78c3479b613686be280f694193d70c406dcf [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Extension Header handling for IPv6
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Andi Kleen <ak@muc.de>
8 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
9 *
10 * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18/* Changes:
19 * yoshfuji : ensure not to overrun while parsing
20 * tlv options.
21 * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
22 * YOSHIFUJI Hideaki @USAGI Register inbound extension header
23 * handlers as inet6_protocol{}.
24 */
25
26#include <linux/errno.h>
27#include <linux/types.h>
28#include <linux/socket.h>
29#include <linux/sockios.h>
30#include <linux/sched.h>
31#include <linux/net.h>
32#include <linux/netdevice.h>
33#include <linux/in6.h>
34#include <linux/icmpv6.h>
35
36#include <net/sock.h>
37#include <net/snmp.h>
38
39#include <net/ipv6.h>
40#include <net/protocol.h>
41#include <net/transp_v6.h>
42#include <net/rawv6.h>
43#include <net/ndisc.h>
44#include <net/ip6_route.h>
45#include <net/addrconf.h>
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -070046#ifdef CONFIG_IPV6_MIP6
47#include <net/xfrm.h>
48#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#include <asm/uaccess.h>
51
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070052int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
53{
54 int packet_len = skb->tail - skb->nh.raw;
55 struct ipv6_opt_hdr *hdr;
56 int len;
57
58 if (offset + 2 > packet_len)
59 goto bad;
60 hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
61 len = ((hdr->hdrlen + 1) << 3);
62
63 if (offset + len > packet_len)
64 goto bad;
65
66 offset += 2;
67 len -= 2;
68
69 while (len > 0) {
70 int opttype = skb->nh.raw[offset];
71 int optlen;
72
73 if (opttype == type)
74 return offset;
75
76 switch (opttype) {
77 case IPV6_TLV_PAD0:
78 optlen = 1;
79 break;
80 default:
81 optlen = skb->nh.raw[offset + 1] + 2;
82 if (optlen > len)
83 goto bad;
84 break;
85 }
86 offset += optlen;
87 len -= optlen;
88 }
89 /* not_found */
Masahide NAKAMURAc61a4042006-08-23 19:18:35 -070090 bad:
91 return -1;
92}
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094/*
95 * Parsing tlv encoded headers.
96 *
97 * Parsing function "func" returns 1, if parsing succeed
98 * and 0, if it failed.
99 * It MUST NOT touch skb->h.
100 */
101
102struct tlvtype_proc {
103 int type;
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700104 int (*func)(struct sk_buff **skbp, int offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105};
106
107/*********************
108 Generic functions
109 *********************/
110
111/* An unknown option is detected, decide what to do */
112
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700113static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700115 struct sk_buff *skb = *skbp;
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
118 case 0: /* ignore */
119 return 1;
120
121 case 1: /* drop packet */
122 break;
123
124 case 3: /* Send ICMP if not a multicast address and drop packet */
125 /* Actually, it is redundant check. icmp_send
126 will recheck in any case.
127 */
128 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
129 break;
130 case 2: /* send ICMP PARM PROB regardless and drop packet */
131 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
132 return 0;
133 };
134
135 kfree_skb(skb);
136 return 0;
137}
138
139/* Parse tlv encoded option header (hop-by-hop or destination) */
140
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700141static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700143 struct sk_buff *skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 struct tlvtype_proc *curr;
145 int off = skb->h.raw - skb->nh.raw;
146 int len = ((skb->h.raw[1]+1)<<3);
147
148 if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
149 goto bad;
150
151 off += 2;
152 len -= 2;
153
154 while (len > 0) {
155 int optlen = skb->nh.raw[off+1]+2;
156
157 switch (skb->nh.raw[off]) {
158 case IPV6_TLV_PAD0:
159 optlen = 1;
160 break;
161
162 case IPV6_TLV_PADN:
163 break;
164
165 default: /* Other TLV code so scan list */
166 if (optlen > len)
167 goto bad;
168 for (curr=procs; curr->type >= 0; curr++) {
169 if (curr->type == skb->nh.raw[off]) {
170 /* type specific length/alignment
171 checks will be performed in the
172 func(). */
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700173 if (curr->func(skbp, off) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return 0;
175 break;
176 }
177 }
178 if (curr->type < 0) {
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700179 if (ip6_tlvopt_unknown(skbp, off) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 return 0;
181 }
182 break;
183 }
184 off += optlen;
185 len -= optlen;
186 }
187 if (len == 0)
188 return 1;
189bad:
190 kfree_skb(skb);
191 return 0;
192}
193
194/*****************************
195 Destination options header.
196 *****************************/
197
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700198#ifdef CONFIG_IPV6_MIP6
199static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
200{
201 struct sk_buff *skb = *skbp;
202 struct ipv6_destopt_hao *hao;
203 struct inet6_skb_parm *opt = IP6CB(skb);
204 struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw;
205 struct in6_addr tmp_addr;
206 int ret;
207
208 if (opt->dsthao) {
209 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
210 goto discard;
211 }
212 opt->dsthao = opt->dst1;
213 opt->dst1 = 0;
214
215 hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
216
217 if (hao->length != 16) {
218 LIMIT_NETDEBUG(
219 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
220 goto discard;
221 }
222
223 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
224 LIMIT_NETDEBUG(
225 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
226 goto discard;
227 }
228
229 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
230 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
231 if (unlikely(ret < 0))
232 goto discard;
233
234 if (skb_cloned(skb)) {
235 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
236 if (skb2 == NULL)
237 goto discard;
238
239 kfree_skb(skb);
240
241 /* update all variable using below by copied skbuff */
242 *skbp = skb = skb2;
243 hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff);
244 ipv6h = (struct ipv6hdr *)skb2->nh.raw;
245 }
246
247 if (skb->ip_summed == CHECKSUM_COMPLETE)
248 skb->ip_summed = CHECKSUM_NONE;
249
250 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
251 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
252 ipv6_addr_copy(&hao->addr, &tmp_addr);
253
254 if (skb->tstamp.off_sec == 0)
255 __net_timestamp(skb);
256
257 return 1;
258
259 discard:
260 kfree_skb(skb);
261 return 0;
262}
263#endif
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static struct tlvtype_proc tlvprocdestopt_lst[] = {
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700266#ifdef CONFIG_IPV6_MIP6
267 {
268 .type = IPV6_TLV_HAO,
269 .func = ipv6_dest_hao,
270 },
271#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 {-1, NULL}
273};
274
Patrick McHardy951dbc82006-01-06 23:02:34 -0800275static int ipv6_destopt_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
277 struct sk_buff *skb = *skbp;
278 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700279#ifdef CONFIG_IPV6_MIP6
280 __u16 dstbuf;
281#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
284 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
285 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
286 kfree_skb(skb);
287 return -1;
288 }
289
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900290 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 opt->dst1 = skb->h.raw - skb->nh.raw;
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700292#ifdef CONFIG_IPV6_MIP6
293 dstbuf = opt->dst1;
294#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700296 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
297 skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 skb->h.raw += ((skb->h.raw[1]+1)<<3);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700299#ifdef CONFIG_IPV6_MIP6
300 opt->nhoff = dstbuf;
301#else
Patrick McHardy951dbc82006-01-06 23:02:34 -0800302 opt->nhoff = opt->dst1;
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700303#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 return 1;
305 }
306
307 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
308 return -1;
309}
310
311static struct inet6_protocol destopt_protocol = {
312 .handler = ipv6_destopt_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700313 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314};
315
316void __init ipv6_destopt_init(void)
317{
318 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
319 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
320}
321
322/********************************
323 NONE header. No data in packet.
324 ********************************/
325
Patrick McHardy951dbc82006-01-06 23:02:34 -0800326static int ipv6_nodata_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 struct sk_buff *skb = *skbp;
329
330 kfree_skb(skb);
331 return 0;
332}
333
334static struct inet6_protocol nodata_protocol = {
335 .handler = ipv6_nodata_rcv,
336 .flags = INET6_PROTO_NOPOLICY,
337};
338
339void __init ipv6_nodata_init(void)
340{
341 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
342 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
343}
344
345/********************************
346 Routing header.
347 ********************************/
348
Patrick McHardy951dbc82006-01-06 23:02:34 -0800349static int ipv6_rthdr_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 struct sk_buff *skb = *skbp;
352 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700353 struct in6_addr *addr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct in6_addr daddr;
355 int n, i;
356
357 struct ipv6_rt_hdr *hdr;
358 struct rt0_hdr *rthdr;
359
360 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
361 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
362 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
363 kfree_skb(skb);
364 return -1;
365 }
366
367 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
368
369 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
370 skb->pkt_type != PACKET_HOST) {
371 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
372 kfree_skb(skb);
373 return -1;
374 }
375
376looped_back:
377 if (hdr->segments_left == 0) {
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700378 switch (hdr->type) {
379#ifdef CONFIG_IPV6_MIP6
380 case IPV6_SRCRT_TYPE_2:
381 /* Silently discard type 2 header unless it was
382 * processed by own
383 */
384 if (!addr) {
385 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
386 kfree_skb(skb);
387 return -1;
388 }
389 break;
390#endif
391 default:
392 break;
393 }
394
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900395 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 opt->srcrt = skb->h.raw - skb->nh.raw;
397 skb->h.raw += (hdr->hdrlen + 1) << 3;
398 opt->dst0 = opt->dst1;
399 opt->dst1 = 0;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800400 opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return 1;
402 }
403
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700404 switch (hdr->type) {
405 case IPV6_SRCRT_TYPE_0:
406 if (hdr->hdrlen & 0x01) {
407 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
408 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
409 return -1;
410 }
411 break;
412#ifdef CONFIG_IPV6_MIP6
413 case IPV6_SRCRT_TYPE_2:
414 /* Silently discard invalid RTH type 2 */
415 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
416 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
417 kfree_skb(skb);
418 return -1;
419 }
420 break;
421#endif
422 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
424 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
425 return -1;
426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 /*
429 * This is the routing header forwarding algorithm from
430 * RFC 2460, page 16.
431 */
432
433 n = hdr->hdrlen >> 1;
434
435 if (hdr->segments_left > n) {
436 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
437 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
438 return -1;
439 }
440
441 /* We are about to mangle packet header. Be careful!
442 Do not damage packets queued somewhere.
443 */
444 if (skb_cloned(skb)) {
445 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
446 kfree_skb(skb);
447 /* the copy is a forwarded packet */
448 if (skb2 == NULL) {
449 IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS);
450 return -1;
451 }
452 *skbp = skb = skb2;
453 opt = IP6CB(skb2);
454 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
455 }
456
Patrick McHardy84fa7932006-08-29 16:44:56 -0700457 if (skb->ip_summed == CHECKSUM_COMPLETE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 skb->ip_summed = CHECKSUM_NONE;
459
460 i = n - --hdr->segments_left;
461
462 rthdr = (struct rt0_hdr *) hdr;
463 addr = rthdr->addr;
464 addr += i - 1;
465
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700466 switch (hdr->type) {
467#ifdef CONFIG_IPV6_MIP6
468 case IPV6_SRCRT_TYPE_2:
469 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
470 (xfrm_address_t *)&skb->nh.ipv6h->saddr,
471 IPPROTO_ROUTING) < 0) {
472 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
473 kfree_skb(skb);
474 return -1;
475 }
476 if (!ipv6_chk_home_addr(addr)) {
477 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
478 kfree_skb(skb);
479 return -1;
480 }
481 break;
482#endif
483 default:
484 break;
485 }
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (ipv6_addr_is_multicast(addr)) {
488 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
489 kfree_skb(skb);
490 return -1;
491 }
492
493 ipv6_addr_copy(&daddr, addr);
494 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
495 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
496
497 dst_release(xchg(&skb->dst, NULL));
498 ip6_route_input(skb);
499 if (skb->dst->error) {
500 skb_push(skb, skb->data - skb->nh.raw);
501 dst_input(skb);
502 return -1;
503 }
504
505 if (skb->dst->dev->flags&IFF_LOOPBACK) {
506 if (skb->nh.ipv6h->hop_limit <= 1) {
507 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
508 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
509 0, skb->dev);
510 kfree_skb(skb);
511 return -1;
512 }
513 skb->nh.ipv6h->hop_limit--;
514 goto looped_back;
515 }
516
517 skb_push(skb, skb->data - skb->nh.raw);
518 dst_input(skb);
519 return -1;
520}
521
522static struct inet6_protocol rthdr_protocol = {
523 .handler = ipv6_rthdr_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700524 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525};
526
527void __init ipv6_rthdr_init(void)
528{
529 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
530 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
531};
532
533/*
534 This function inverts received rthdr.
535 NOTE: specs allow to make it automatically only if
536 packet authenticated.
537
538 I will not discuss it here (though, I am really pissed off at
539 this stupid requirement making rthdr idea useless)
540
541 Actually, it creates severe problems for us.
542 Embryonic requests has no associated sockets,
543 so that user have no control over it and
544 cannot not only to set reply options, but
545 even to know, that someone wants to connect
546 without success. :-(
547
548 For now we need to test the engine, so that I created
549 temporary (or permanent) backdoor.
550 If listening socket set IPV6_RTHDR to 2, then we invert header.
551 --ANK (980729)
552 */
553
554struct ipv6_txoptions *
555ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
556{
557 /* Received rthdr:
558
559 [ H1 -> H2 -> ... H_prev ] daddr=ME
560
561 Inverted result:
562 [ H_prev -> ... -> H1 ] daddr =sender
563
564 Note, that IP output engine will rewrite this rthdr
565 by rotating it left by one addr.
566 */
567
568 int n, i;
569 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
570 struct rt0_hdr *irthdr;
571 struct ipv6_txoptions *opt;
572 int hdrlen = ipv6_optlen(hdr);
573
574 if (hdr->segments_left ||
575 hdr->type != IPV6_SRCRT_TYPE_0 ||
576 hdr->hdrlen & 0x01)
577 return NULL;
578
579 n = hdr->hdrlen >> 1;
580 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
581 if (opt == NULL)
582 return NULL;
583 memset(opt, 0, sizeof(*opt));
584 opt->tot_len = sizeof(*opt) + hdrlen;
585 opt->srcrt = (void*)(opt+1);
586 opt->opt_nflen = hdrlen;
587
588 memcpy(opt->srcrt, hdr, sizeof(*hdr));
589 irthdr = (struct rt0_hdr*)opt->srcrt;
Brian Haleye6df4392005-09-10 00:15:06 -0700590 irthdr->reserved = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 opt->srcrt->segments_left = n;
592 for (i=0; i<n; i++)
593 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
594 return opt;
595}
596
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800597EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599/**********************************
600 Hop-by-hop options.
601 **********************************/
602
603/* Router Alert as of RFC 2711 */
604
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700605static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700607 struct sk_buff *skb = *skbp;
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 if (skb->nh.raw[optoff+1] == 2) {
610 IP6CB(skb)->ra = optoff;
611 return 1;
612 }
Patrick McHardy64ce2072005-08-09 20:50:53 -0700613 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
614 skb->nh.raw[optoff+1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 kfree_skb(skb);
616 return 0;
617}
618
619/* Jumbo payload */
620
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700621static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700623 struct sk_buff *skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 u32 pkt_len;
625
626 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700627 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
628 skb->nh.raw[optoff+1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
630 goto drop;
631 }
632
633 pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
634 if (pkt_len <= IPV6_MAXPLEN) {
635 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
636 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
637 return 0;
638 }
639 if (skb->nh.ipv6h->payload_len) {
640 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
641 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
642 return 0;
643 }
644
645 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
646 IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
647 goto drop;
648 }
Stephen Hemminger42ca89c2005-09-08 12:57:43 -0700649
650 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
651 goto drop;
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 return 1;
654
655drop:
656 kfree_skb(skb);
657 return 0;
658}
659
660static struct tlvtype_proc tlvprochopopt_lst[] = {
661 {
662 .type = IPV6_TLV_ROUTERALERT,
663 .func = ipv6_hop_ra,
664 },
665 {
666 .type = IPV6_TLV_JUMBO,
667 .func = ipv6_hop_jumbo,
668 },
669 { -1, }
670};
671
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700672int ipv6_parse_hopopts(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700674 struct sk_buff *skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800675 struct inet6_skb_parm *opt = IP6CB(skb);
676
YOSHIFUJI Hideakiec670092006-04-18 14:46:26 -0700677 /*
678 * skb->nh.raw is equal to skb->data, and
679 * skb->h.raw - skb->nh.raw is always equal to
680 * sizeof(struct ipv6hdr) by definition of
681 * hop-by-hop options.
682 */
683 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
684 !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
685 kfree_skb(skb);
686 return -1;
687 }
688
Patrick McHardy951dbc82006-01-06 23:02:34 -0800689 opt->hop = sizeof(struct ipv6hdr);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700690 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
691 skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800692 skb->h.raw += (skb->h.raw[1]+1)<<3;
693 opt->nhoff = sizeof(struct ipv6hdr);
YOSHIFUJI Hideakib8097392006-04-18 14:48:45 -0700694 return 1;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return -1;
697}
698
699/*
700 * Creating outbound headers.
701 *
702 * "build" functions work when skb is filled from head to tail (datagram)
703 * "push" functions work when headers are added from tail to head (tcp)
704 *
705 * In both cases we assume, that caller reserved enough room
706 * for headers.
707 */
708
709static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
710 struct ipv6_rt_hdr *opt,
711 struct in6_addr **addr_p)
712{
713 struct rt0_hdr *phdr, *ihdr;
714 int hops;
715
716 ihdr = (struct rt0_hdr *) opt;
717
718 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
719 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
720
721 hops = ihdr->rt_hdr.hdrlen >> 1;
722
723 if (hops > 1)
724 memcpy(phdr->addr, ihdr->addr + 1,
725 (hops - 1) * sizeof(struct in6_addr));
726
727 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
728 *addr_p = ihdr->addr;
729
730 phdr->rt_hdr.nexthdr = *proto;
731 *proto = NEXTHDR_ROUTING;
732}
733
734static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
735{
736 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
737
738 memcpy(h, opt, ipv6_optlen(opt));
739 h->nexthdr = *proto;
740 *proto = type;
741}
742
743void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
744 u8 *proto,
745 struct in6_addr **daddr)
746{
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900747 if (opt->srcrt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900749 /*
750 * IPV6_RTHDRDSTOPTS is ignored
751 * unless IPV6_RTHDR is set (RFC3542).
752 */
753 if (opt->dst0opt)
754 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (opt->hopopt)
757 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
758}
759
760void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
761{
762 if (opt->dst1opt)
763 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
764}
765
766struct ipv6_txoptions *
767ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
768{
769 struct ipv6_txoptions *opt2;
770
771 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
772 if (opt2) {
773 long dif = (char*)opt2 - (char*)opt;
774 memcpy(opt2, opt, opt->tot_len);
775 if (opt2->hopopt)
776 *((char**)&opt2->hopopt) += dif;
777 if (opt2->dst0opt)
778 *((char**)&opt2->dst0opt) += dif;
779 if (opt2->dst1opt)
780 *((char**)&opt2->dst1opt) += dif;
781 if (opt2->srcrt)
782 *((char**)&opt2->srcrt) += dif;
783 }
784 return opt2;
785}
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900786
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800787EXPORT_SYMBOL_GPL(ipv6_dup_options);
788
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900789static int ipv6_renew_option(void *ohdr,
790 struct ipv6_opt_hdr __user *newopt, int newoptlen,
791 int inherit,
792 struct ipv6_opt_hdr **hdr,
793 char **p)
794{
795 if (inherit) {
796 if (ohdr) {
797 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
798 *hdr = (struct ipv6_opt_hdr *)*p;
799 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
800 }
801 } else {
802 if (newopt) {
803 if (copy_from_user(*p, newopt, newoptlen))
804 return -EFAULT;
805 *hdr = (struct ipv6_opt_hdr *)*p;
806 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
807 return -EINVAL;
808 *p += CMSG_ALIGN(newoptlen);
809 }
810 }
811 return 0;
812}
813
814struct ipv6_txoptions *
815ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
816 int newtype,
817 struct ipv6_opt_hdr __user *newopt, int newoptlen)
818{
819 int tot_len = 0;
820 char *p;
821 struct ipv6_txoptions *opt2;
822 int err;
823
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700824 if (opt) {
825 if (newtype != IPV6_HOPOPTS && opt->hopopt)
826 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
827 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
828 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
829 if (newtype != IPV6_RTHDR && opt->srcrt)
830 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
831 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
832 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
833 }
834
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900835 if (newopt && newoptlen)
836 tot_len += CMSG_ALIGN(newoptlen);
837
838 if (!tot_len)
839 return NULL;
840
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900841 tot_len += sizeof(*opt2);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900842 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
843 if (!opt2)
844 return ERR_PTR(-ENOBUFS);
845
846 memset(opt2, 0, tot_len);
847
848 opt2->tot_len = tot_len;
849 p = (char *)(opt2 + 1);
850
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700851 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900852 newtype != IPV6_HOPOPTS,
853 &opt2->hopopt, &p);
854 if (err)
855 goto out;
856
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700857 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900858 newtype != IPV6_RTHDRDSTOPTS,
859 &opt2->dst0opt, &p);
860 if (err)
861 goto out;
862
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700863 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900864 newtype != IPV6_RTHDR,
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700865 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900866 if (err)
867 goto out;
868
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700869 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900870 newtype != IPV6_DSTOPTS,
871 &opt2->dst1opt, &p);
872 if (err)
873 goto out;
874
875 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
876 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
877 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
878 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
879
880 return opt2;
881out:
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900882 sock_kfree_s(sk, opt2, opt2->tot_len);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900883 return ERR_PTR(err);
884}
885
YOSHIFUJI Hideakidf9890c2005-11-20 12:23:18 +0900886struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
887 struct ipv6_txoptions *opt)
888{
889 /*
890 * ignore the dest before srcrt unless srcrt is being included.
891 * --yoshfuji
892 */
893 if (opt && opt->dst0opt && !opt->srcrt) {
894 if (opt_space != opt) {
895 memcpy(opt_space, opt, sizeof(*opt_space));
896 opt = opt_space;
897 }
898 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
899 opt->dst0opt = NULL;
900 }
901
902 return opt;
903}
904