1 /*
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.10 2000/01/09 02:19:55 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 #include <linux/errno.h>
19 #include <linux/types.h>
20 #include <linux/socket.h>
21 #include <linux/sockios.h>
22 #include <linux/sched.h>
23 #include <linux/net.h>
24 #include <linux/netdevice.h>
25 #include <linux/in6.h>
26 #include <linux/icmpv6.h>
27
28 #include <net/sock.h>
29 #include <net/snmp.h>
30
31 #include <net/ipv6.h>
32 #include <net/protocol.h>
33 #include <net/transp_v6.h>
34 #include <net/rawv6.h>
35 #include <net/ndisc.h>
36 #include <net/ip6_route.h>
37 #include <net/addrconf.h>
38
39 #include <asm/uaccess.h>
40
41 /*
42 * Parsing inbound headers.
43 *
44 * Parsing function "func" returns pointer to the place,
45 * where next nexthdr value is stored or NULL, if parsing
46 * failed. It should also update skb->h.
47 */
48
49 struct hdrtype_proc
50 {
51 int type;
52 u8* (*func) (struct sk_buff **, u8 *ptr);
53 };
54
55 /*
56 * Parsing tlv encoded headers.
57 *
58 * Parsing function "func" returns 1, if parsing succeed
59 * and 0, if it failed.
60 * It MUST NOT touch skb->h.
61 */
62
63 struct tlvtype_proc
64 {
65 int type;
66 int (*func) (struct sk_buff *, __u8 *ptr);
67 };
68
69 /*********************
70 Generic functions
71 *********************/
72
73 /* An unknown option is detected, decide what to do */
74
75 int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt)
76 {
77 switch ((opt[0] & 0xC0) >> 6) {
78 case 0: /* ignore */
79 return 1;
80
81 case 1: /* drop packet */
82 break;
83
84 case 3: /* Send ICMP if not a multicast address and drop packet */
85 /* Actually, it is redundant check. icmp_send
86 will recheck in any case.
87 */
88 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
89 break;
90 case 2: /* send ICMP PARM PROB regardless and drop packet */
91 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, opt);
92 return 0;
93 };
94
95 kfree_skb(skb);
96 return 0;
97 }
98
99 /* Parse tlv encoded option header (hop-by-hop or destination) */
100
101 static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
102 __u8 *nhptr)
103 {
104 struct tlvtype_proc *curr;
105 u8 *ptr = skb->h.raw;
106 int len = ((ptr[1]+1)<<3) - 2;
107
108 ptr += 2;
109
110 if (skb->tail - (ptr + len) < 0) {
111 kfree_skb(skb);
112 return 0;
113 }
114
115 while (len > 0) {
116 int optlen = ptr[1]+2;
117
118 switch (ptr[0]) {
119 case IPV6_TLV_PAD0:
120 optlen = 1;
121 break;
122
123 case IPV6_TLV_PADN:
124 break;
125
126 default: /* Other TLV code so scan list */
127 for (curr=procs; curr->type >= 0; curr++) {
128 if (curr->type == ptr[0]) {
129 if (curr->func(skb, ptr) == 0)
130 return 0;
131 break;
132 }
133 }
134 if (curr->type < 0) {
135 if (ip6_tlvopt_unknown(skb, ptr) == 0)
136 return 0;
137 }
138 break;
139 }
140 ptr += optlen;
141 len -= optlen;
142 }
143 if (len == 0)
144 return 1;
145 kfree_skb(skb);
146 return 0;
147 }
148
149 /*****************************
150 Destination options header.
151 *****************************/
152
153 struct tlvtype_proc tlvprocdestopt_lst[] = {
154 /* No destination options are defined now */
155 {-1, NULL}
156 };
157
158 static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr)
159 {
160 struct sk_buff *skb=*skb_ptr;
161 struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
162 struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
163
164 opt->dst1 = (u8*)hdr - skb->nh.raw;
165
166 if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) {
167 skb->h.raw += ((hdr->hdrlen+1)<<3);
168 return &hdr->nexthdr;
169 }
170
171 return NULL;
172 }
173
174 /********************************
175 NONE header. No data in packet.
176 ********************************/
177
178 static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr)
179 {
180 kfree_skb(*skb_ptr);
181 return NULL;
182 }
183
184 /********************************
185 Routing header.
186 ********************************/
187
188 static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr)
189 {
190 struct sk_buff *skb = *skb_ptr;
191 struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
192 struct in6_addr *addr;
193 struct in6_addr daddr;
194 int addr_type;
195 int n, i;
196
197 struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw;
198 struct rt0_hdr *rthdr;
199
200 if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) {
201 IP6_INC_STATS_BH(Ip6InHdrErrors);
202 kfree_skb(skb);
203 return NULL;
204 }
205
206 looped_back:
207 if (hdr->segments_left == 0) {
208 opt->srcrt = (u8*)hdr - skb->nh.raw;
209 skb->h.raw += (hdr->hdrlen + 1) << 3;
210 opt->dst0 = opt->dst1;
211 opt->dst1 = 0;
212 return &hdr->nexthdr;
213 }
214
215 if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) {
216 u8 *pos = (u8*) hdr;
217
218 if (hdr->type != IPV6_SRCRT_TYPE_0)
219 pos += 2;
220 else
221 pos += 1;
222
223 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos);
224 return NULL;
225 }
226
227 /*
228 * This is the routing header forwarding algorithm from
229 * RFC 1883, page 17.
230 */
231
232 n = hdr->hdrlen >> 1;
233
234 if (hdr->segments_left > n) {
235 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left);
236 return NULL;
237 }
238
239 /* We are about to mangle packet header. Be careful!
240 Do not damage packets queued somewhere.
241 */
242 if (skb_cloned(skb)) {
243 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
244 kfree_skb(skb);
245 if (skb2 == NULL)
246 return NULL;
247 *skb_ptr = skb = skb2;
248 opt = (struct inet6_skb_parm *)skb2->cb;
249 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
250 }
251
252 i = n - --hdr->segments_left;
253
254 rthdr = (struct rt0_hdr *) hdr;
255 addr = rthdr->addr;
256 addr += i - 1;
257
258 addr_type = ipv6_addr_type(addr);
259
260 if (addr_type == IPV6_ADDR_MULTICAST) {
261 kfree_skb(skb);
262 return NULL;
263 }
264
265 ipv6_addr_copy(&daddr, addr);
266 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
267 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
268
269 dst_release(xchg(&skb->dst, NULL));
270 ip6_route_input(skb);
271 if (skb->dst->error) {
272 skb->dst->input(skb);
273 return NULL;
274 }
275 if (skb->dst->dev->flags&IFF_LOOPBACK) {
276 if (skb->nh.ipv6h->hop_limit <= 1) {
277 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
278 0, skb->dev);
279 kfree_skb(skb);
280 return NULL;
281 }
282 skb->nh.ipv6h->hop_limit--;
283 goto looped_back;
284 }
285
286 skb->dst->input(skb);
287 return NULL;
288 }
289
290 /*
291 This function inverts received rthdr.
292 NOTE: specs allow to make it automatically only if
293 packet authenticated.
294
295 I will not discuss it here (though, I am really pissed off at
296 this stupid requirement making rthdr idea useless)
297
298 Actually, it creates severe problems for us.
299 Embrionic requests has no associated sockets,
300 so that user have no control over it and
301 cannot not only to set reply options, but
302 even to know, that someone wants to connect
303 without success. :-(
304
305 For now we need to test the engine, so that I created
306 temporary (or permanent) backdoor.
307 If listening socket set IPV6_RTHDR to 2, then we invert header.
308 --ANK (980729)
309 */
310
311 struct ipv6_txoptions *
312 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
313 {
314 /* Received rthdr:
315
316 [ H1 -> H2 -> ... H_prev ] daddr=ME
317
318 Inverted result:
319 [ H_prev -> ... -> H1 ] daddr =sender
320
321 Note, that IP output engine will rewrire this rthdr
322 by rotating it left by one addr.
323 */
324
325 int n, i;
326 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
327 struct rt0_hdr *irthdr;
328 struct ipv6_txoptions *opt;
329 int hdrlen = ipv6_optlen(hdr);
330
331 if (hdr->segments_left ||
332 hdr->type != IPV6_SRCRT_TYPE_0 ||
333 hdr->hdrlen & 0x01)
334 return NULL;
335
336 n = hdr->hdrlen >> 1;
337 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
338 if (opt == NULL)
339 return NULL;
340 memset(opt, 0, sizeof(*opt));
341 opt->tot_len = sizeof(*opt) + hdrlen;
342 opt->srcrt = (void*)(opt+1);
343 opt->opt_nflen = hdrlen;
344
345 memcpy(opt->srcrt, hdr, sizeof(*hdr));
346 irthdr = (struct rt0_hdr*)opt->srcrt;
347 /* Obsolete field, MBZ, when originated by us */
348 irthdr->bitmap = 0;
349 opt->srcrt->segments_left = n;
350 for (i=0; i<n; i++)
351 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
352 return opt;
353 }
354
355 /********************************
356 AUTH header.
357 ********************************/
358
359 /*
360 rfc1826 said, that if a host does not implement AUTH header
361 it MAY ignore it. We use this hole 8)
362
363 Actually, now we can implement OSPFv6 without kernel IPsec.
364 Authentication for poors may be done in user space with the same success.
365
366 Yes, it means, that we allow application to send/receive
367 raw authentication header. Apparently, we suppose, that it knows
368 what it does and calculates authentication data correctly.
369 Certainly, it is possible only for udp and raw sockets, but not for tcp.
370
371 AUTH header has 4byte granular length, which kills all the idea
372 behind AUTOMATIC 64bit alignment of IPv6. Now we will lose
373 cpu ticks, checking that sender did not something stupid
374 and opt->hdrlen is even. Shit! --ANK (980730)
375 */
376
377 static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr)
378 {
379 struct sk_buff *skb=*skb_ptr;
380 struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
381 struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw;
382 int len = (hdr->hdrlen+2)<<2;
383
384 if (len&7)
385 return NULL;
386 opt->auth = (u8*)hdr - skb->nh.raw;
387 if (skb->h.raw + len > skb->tail)
388 return NULL;
389 skb->h.raw += len;
390 return &hdr->nexthdr;
391 }
392
393 /* This list MUST NOT contain entry for NEXTHDR_HOP.
394 It is parsed immediately after packet received
395 and if it occurs somewhere in another place we must
396 generate error.
397 */
398
399 struct hdrtype_proc hdrproc_lst[] = {
400 {NEXTHDR_FRAGMENT, ipv6_reassembly},
401 {NEXTHDR_ROUTING, ipv6_routing_header},
402 {NEXTHDR_DEST, ipv6_dest_opt},
403 {NEXTHDR_NONE, ipv6_nodata},
404 {NEXTHDR_AUTH, ipv6_auth_hdr},
405 /*
406 {NEXTHDR_ESP, ipv6_esp_hdr},
407 */
408 {-1, NULL}
409 };
410
411 u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr)
412 {
413 struct hdrtype_proc *hdrt;
414 u8 nexthdr = *nhptr;
415
416 restart:
417 for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
418 if (hdrt->type == nexthdr) {
419 if ((nhptr = hdrt->func(skb_in, nhptr)) != NULL) {
420 nexthdr = *nhptr;
421 goto restart;
422 }
423 return NULL;
424 }
425 }
426 return nhptr;
427 }
428
429
430 /**********************************
431 Hop-by-hop options.
432 **********************************/
433
434 /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
435
436 static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr)
437 {
438 if (ptr[1] == 2) {
439 ((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw;
440 return 1;
441 }
442 if (net_ratelimit())
443 printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", ptr[1]);
444 kfree_skb(skb);
445 return 0;
446 }
447
448 /* Jumbo payload */
449
450 static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr)
451 {
452 u32 pkt_len;
453
454 if (ptr[1] != 4 || ((ptr-skb->nh.raw)&3) != 2) {
455 if (net_ratelimit())
456 printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", ptr[1]);
457 goto drop;
458 }
459
460 pkt_len = ntohl(*(u32*)(ptr+2));
461 if (pkt_len < 0x10000) {
462 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr+2);
463 return 0;
464 }
465 if (skb->nh.ipv6h->payload_len) {
466 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr);
467 return 0;
468 }
469
470 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
471 IP6_INC_STATS_BH(Ip6InTruncatedPkts);
472 goto drop;
473 }
474 skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
475 return 1;
476
477 drop:
478 kfree_skb(skb);
479 return 0;
480 }
481
482 struct tlvtype_proc tlvprochopopt_lst[] = {
483 {IPV6_TLV_ROUTERALERT, ipv6_hop_ra},
484 {IPV6_TLV_JUMBO, ipv6_hop_jumbo},
485 {-1, NULL}
486 };
487
488 u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr)
489 {
490 ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr);
491 if (ip6_parse_tlv(tlvprochopopt_lst, skb, nhptr))
492 return nhptr+((nhptr[1]+1)<<3);
493 return NULL;
494 }
495
496 /*
497 * Creating outbound headers.
498 *
499 * "build" functions work when skb is filled from head to tail (datagram)
500 * "push" functions work when headers are added from tail to head (tcp)
501 *
502 * In both cases we assume, that caller reserved enough room
503 * for headers.
504 */
505
506 u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
507 struct ipv6_rt_hdr *opt, struct in6_addr *addr)
508 {
509 struct rt0_hdr *phdr, *ihdr;
510 int hops;
511
512 ihdr = (struct rt0_hdr *) opt;
513
514 phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
515 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
516
517 hops = ihdr->rt_hdr.hdrlen >> 1;
518
519 if (hops > 1)
520 memcpy(phdr->addr, ihdr->addr + 1,
521 (hops - 1) * sizeof(struct in6_addr));
522
523 ipv6_addr_copy(phdr->addr + (hops - 1), addr);
524
525 phdr->rt_hdr.nexthdr = *prev_hdr;
526 *prev_hdr = NEXTHDR_ROUTING;
527 return &phdr->rt_hdr.nexthdr;
528 }
529
530 static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
531 {
532 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
533
534 memcpy(h, opt, ipv6_optlen(opt));
535 h->nexthdr = *prev_hdr;
536 *prev_hdr = type;
537 return &h->nexthdr;
538 }
539
540 static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
541 {
542 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
543
544 memcpy(h, opt, (opt->hdrlen+2)<<2);
545 h->nexthdr = *prev_hdr;
546 *prev_hdr = NEXTHDR_AUTH;
547 return &h->nexthdr;
548 }
549
550
551 u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
552 struct in6_addr *daddr, u32 jumbolen)
553 {
554 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
555
556 if (opt && opt->hopopt)
557 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
558
559 if (jumbolen) {
560 u8 *jumboopt = (u8 *)skb_put(skb, 8);
561
562 if (opt && opt->hopopt) {
563 *jumboopt++ = IPV6_TLV_PADN;
564 *jumboopt++ = 0;
565 h->hdrlen++;
566 } else {
567 h = (struct ipv6_opt_hdr *)jumboopt;
568 h->nexthdr = *prev_hdr;
569 h->hdrlen = 0;
570 jumboopt += 2;
571 *prev_hdr = NEXTHDR_HOP;
572 prev_hdr = &h->nexthdr;
573 }
574 jumboopt[0] = IPV6_TLV_JUMBO;
575 jumboopt[1] = 4;
576 *(u32*)(jumboopt+2) = htonl(jumbolen);
577 }
578 if (opt) {
579 if (opt->dst0opt)
580 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
581 if (opt->srcrt)
582 prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
583 }
584 return prev_hdr;
585 }
586
587 u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
588 {
589 if (opt->auth)
590 prev_hdr = ipv6_build_authhdr(skb, prev_hdr, opt->auth);
591 if (opt->dst1opt)
592 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
593 return prev_hdr;
594 }
595
596 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
597 struct ipv6_rt_hdr *opt,
598 struct in6_addr **addr_p)
599 {
600 struct rt0_hdr *phdr, *ihdr;
601 int hops;
602
603 ihdr = (struct rt0_hdr *) opt;
604
605 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
606 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
607
608 hops = ihdr->rt_hdr.hdrlen >> 1;
609
610 if (hops > 1)
611 memcpy(phdr->addr, ihdr->addr + 1,
612 (hops - 1) * sizeof(struct in6_addr));
613
614 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
615 *addr_p = ihdr->addr;
616
617 phdr->rt_hdr.nexthdr = *proto;
618 *proto = NEXTHDR_ROUTING;
619 }
620
621 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
622 {
623 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
624
625 memcpy(h, opt, ipv6_optlen(opt));
626 h->nexthdr = *proto;
627 *proto = type;
628 }
629
630 static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
631 {
632 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
633
634 memcpy(h, opt, (opt->hdrlen+2)<<2);
635 h->nexthdr = *proto;
636 *proto = NEXTHDR_AUTH;
637 }
638
639 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
640 u8 *proto,
641 struct in6_addr **daddr)
642 {
643 if (opt->srcrt)
644 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
645 if (opt->dst0opt)
646 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
647 if (opt->hopopt)
648 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
649 }
650
651 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
652 {
653 if (opt->dst1opt)
654 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
655 if (opt->auth)
656 ipv6_push_authhdr(skb, proto, opt->auth);
657 }
658
659 struct ipv6_txoptions *
660 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
661 {
662 struct ipv6_txoptions *opt2;
663
664 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
665 if (opt2) {
666 long dif = (char*)opt2 - (char*)opt;
667 memcpy(opt2, opt, opt->tot_len);
668 if (opt2->hopopt)
669 *((char**)&opt2->hopopt) += dif;
670 if (opt2->dst0opt)
671 *((char**)&opt2->dst0opt) += dif;
672 if (opt2->dst1opt)
673 *((char**)&opt2->dst1opt) += dif;
674 if (opt2->auth)
675 *((char**)&opt2->auth) += dif;
676 if (opt2->srcrt)
677 *((char**)&opt2->srcrt) += dif;
678 }
679 return opt2;
680 }
681
682
683 /*
684 * find out if nexthdr is a well-known extension header or a protocol
685 */
686
687 static __inline__ int ipv6_ext_hdr(u8 nexthdr)
688 {
689 /*
690 * find out if nexthdr is an extension header or a protocol
691 */
692 return ( (nexthdr == NEXTHDR_HOP) ||
693 (nexthdr == NEXTHDR_ROUTING) ||
694 (nexthdr == NEXTHDR_FRAGMENT) ||
695 (nexthdr == NEXTHDR_AUTH) ||
696 (nexthdr == NEXTHDR_NONE) ||
697 (nexthdr == NEXTHDR_DEST) );
698 }
699
700 /*
701 * Skip any extension headers. This is used by the ICMP module.
702 *
703 * Note that strictly speaking this conflicts with RFC1883 4.0:
704 * ...The contents and semantics of each extension header determine whether
705 * or not to proceed to the next header. Therefore, extension headers must
706 * be processed strictly in the order they appear in the packet; a
707 * receiver must not, for example, scan through a packet looking for a
708 * particular kind of extension header and process that header prior to
709 * processing all preceding ones.
710 *
711 * We do exactly this. This is a protocol bug. We can't decide after a
712 * seeing an unknown discard-with-error flavour TLV option if it's a
713 * ICMP error message or not (errors should never be send in reply to
714 * ICMP error messages).
715 *
716 * But I see no other way to do this. This might need to be reexamined
717 * when Linux implements ESP (and maybe AUTH) headers.
718 * --AK
719 *
720 * This function parses (probably truncated) exthdr set "hdr"
721 * of length "len". "nexthdrp" initially points to some place,
722 * where type of the first header can be found.
723 *
724 * It skips all well-known exthdrs, and returns pointer to the start
725 * of unparsable area i.e. the first header with unknown type.
726 * If it is not NULL *nexthdr is updated by type/protocol of this header.
727 *
728 * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
729 * - it may return pointer pointing beyond end of packet,
730 * if the last recognized header is truncated in the middle.
731 * - if packet is truncated, so that all parsed headers are skipped,
732 * it returns NULL.
733 * - First fragment header is skipped, not-first ones
734 * are considered as unparsable.
735 * - ESP is unparsable for now and considered like
736 * normal payload protocol.
737 * - Note also special handling of AUTH header. Thanks to IPsec wizards.
738 *
739 * --ANK (980726)
740 */
741
742 u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len)
743 {
744 u8 nexthdr = *nexthdrp;
745
746 while (ipv6_ext_hdr(nexthdr)) {
747 int hdrlen;
748
749 if (len < sizeof(struct ipv6_opt_hdr))
750 return NULL;
751 if (nexthdr == NEXTHDR_NONE)
752 return NULL;
753 if (nexthdr == NEXTHDR_FRAGMENT) {
754 struct frag_hdr *fhdr = (struct frag_hdr *) hdr;
755 if (ntohs(fhdr->frag_off) & ~0x7)
756 break;
757 hdrlen = 8;
758 } else if (nexthdr == NEXTHDR_AUTH)
759 hdrlen = (hdr->hdrlen+2)<<2;
760 else
761 hdrlen = ipv6_optlen(hdr);
762
763 nexthdr = hdr->nexthdr;
764 hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen);
765 len -= hdrlen;
766 }
767
768 *nexthdrp = nexthdr;
769 return (u8*)hdr;
770 }
771
772
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.