Import 2.3.10pre1
[davej-history.git] / net / ipv6 / exthdrs.c
blob5fb91539061653c96838073d42ed206ec6eb2a7e
1 /*
2 * Extension Header handling for IPv6
3 * Linux INET6 implementation
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Andi Kleen <ak@muc.de>
8 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
10 * $Id: exthdrs.c,v 1.9 1999/05/17 23:47:35 davem Exp $
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.
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>
28 #include <net/sock.h>
29 #include <net/snmp.h>
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>
39 #include <asm/uaccess.h>
42 * Parsing inbound headers.
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.
49 struct hdrtype_proc
51 int type;
52 u8* (*func) (struct sk_buff **, u8 *ptr);
56 * Parsing tlv encoded headers.
58 * Parsing function "func" returns 1, if parsing succeed
59 * and 0, if it failed.
60 * It MUST NOT touch skb->h.
63 struct tlvtype_proc
65 int type;
66 int (*func) (struct sk_buff *, __u8 *ptr);
69 /*********************
70 Generic functions
71 *********************/
73 /* An unknown option is detected, decide what to do */
75 int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt)
77 switch ((opt[0] & 0xC0) >> 6) {
78 case 0: /* ignore */
79 return 1;
81 case 1: /* drop packet */
82 break;
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.
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;
95 kfree_skb(skb);
96 return 0;
99 /* Parse tlv encoded option header (hop-by-hop or destination) */
101 static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
102 __u8 *nhptr)
104 struct tlvtype_proc *curr;
105 u8 *ptr = skb->h.raw;
106 int len = ((ptr[1]+1)<<3) - 2;
108 ptr += 2;
110 if (skb->tail - (ptr + len) < 0) {
111 kfree_skb(skb);
112 return 0;
115 while (len > 0) {
116 int optlen = ptr[1]+2;
118 switch (ptr[0]) {
119 case IPV6_TLV_PAD0:
120 optlen = 1;
121 break;
123 case IPV6_TLV_PADN:
124 break;
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;
134 if (curr->type < 0) {
135 if (ip6_tlvopt_unknown(skb, ptr) == 0)
136 return 0;
138 break;
140 ptr += optlen;
141 len -= optlen;
143 if (len == 0)
144 return 1;
145 kfree_skb(skb);
146 return 0;
149 /*****************************
150 Destination options header.
151 *****************************/
153 struct tlvtype_proc tlvprocdestopt_lst[] = {
154 /* No destination options are defined now */
155 {-1, NULL}
158 static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr)
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;
164 opt->dst1 = (u8*)hdr - skb->nh.raw;
166 if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) {
167 skb->h.raw += ((hdr->hdrlen+1)<<3);
168 return &hdr->nexthdr;
171 return NULL;
174 /********************************
175 NONE header. No data in packet.
176 ********************************/
178 static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr)
180 kfree_skb(*skb_ptr);
181 return NULL;
184 /********************************
185 Routing header.
186 ********************************/
188 static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr)
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;
197 struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw;
198 struct rt0_hdr *rthdr;
200 if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) {
201 ipv6_statistics.Ip6InHdrErrors++;
202 kfree_skb(skb);
203 return NULL;
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;
215 if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) {
216 u8 *pos = (u8*) hdr;
218 if (hdr->type != IPV6_SRCRT_TYPE_0)
219 pos += 2;
220 else
221 pos += 1;
223 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos);
224 return NULL;
228 * This is the routing header forwarding algorithm from
229 * RFC 1883, page 17.
232 n = hdr->hdrlen >> 1;
234 if (hdr->segments_left > n) {
235 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left);
236 return NULL;
239 /* We are about to mangle packet header. Be careful!
240 Do not damage packets queued somewhere.
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;
252 i = n - --hdr->segments_left;
254 rthdr = (struct rt0_hdr *) hdr;
255 addr = rthdr->addr;
256 addr += i - 1;
258 addr_type = ipv6_addr_type(addr);
260 if (addr_type == IPV6_ADDR_MULTICAST) {
261 kfree_skb(skb);
262 return NULL;
265 ipv6_addr_copy(&daddr, addr);
266 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
267 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
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;
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;
282 skb->nh.ipv6h->hop_limit--;
283 goto looped_back;
286 skb->dst->input(skb);
287 return NULL;
291 This function inverts received rthdr.
292 NOTE: specs allow to make it automatically only if
293 packet authenticated.
295 I will not discuss it here (though, I am really pissed off at
296 this stupid requirement making rthdr idea useless)
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. :-(
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)
311 struct ipv6_txoptions *
312 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
314 /* Received rthdr:
316 [ H1 -> H2 -> ... H_prev ] daddr=ME
318 Inverted result:
319 [ H_prev -> ... -> H1 ] daddr =sender
321 Note, that IP output engine will rewrire this rthdr
322 by rotating it left by one addr.
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);
331 if (hdr->segments_left ||
332 hdr->type != IPV6_SRCRT_TYPE_0 ||
333 hdr->hdrlen & 0x01)
334 return NULL;
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;
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;
355 /********************************
356 AUTH header.
357 ********************************/
360 rfc1826 said, that if a host does not implement AUTH header
361 it MAY ignore it. We use this hole 8)
363 Actually, now we can implement OSPFv6 without kernel IPsec.
364 Authentication for poors may be done in user space with the same success.
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.
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)
377 static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr)
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;
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;
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.
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},
406 {NEXTHDR_ESP, ipv6_esp_hdr},
408 {-1, NULL}
411 u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr)
413 struct hdrtype_proc *hdrt;
414 u8 nexthdr = *nhptr;
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;
423 return NULL;
426 return nhptr;
430 /**********************************
431 Hop-by-hop options.
432 **********************************/
434 /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
436 static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr)
438 if (ptr[1] == 2) {
439 ((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw;
440 return 1;
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;
448 /* Jumbo payload */
450 static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr)
452 u32 pkt_len;
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;
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;
465 if (skb->nh.ipv6h->payload_len) {
466 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr);
467 return 0;
470 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
471 ipv6_statistics.Ip6InTruncatedPkts++;
472 goto drop;
474 skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
475 return 1;
477 drop:
478 kfree_skb(skb);
479 return 0;
482 struct tlvtype_proc tlvprochopopt_lst[] = {
483 {IPV6_TLV_ROUTERALERT, ipv6_hop_ra},
484 {IPV6_TLV_JUMBO, ipv6_hop_jumbo},
485 {-1, NULL}
488 u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr)
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;
497 * Creating outbound headers.
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)
502 * In both cases we assume, that caller reserved enough room
503 * for headers.
506 u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
507 struct ipv6_rt_hdr *opt, struct in6_addr *addr)
509 struct rt0_hdr *phdr, *ihdr;
510 int hops;
512 ihdr = (struct rt0_hdr *) opt;
514 phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
515 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
517 hops = ihdr->rt_hdr.hdrlen >> 1;
519 if (hops > 1)
520 memcpy(phdr->addr, ihdr->addr + 1,
521 (hops - 1) * sizeof(struct in6_addr));
523 ipv6_addr_copy(phdr->addr + (hops - 1), addr);
525 phdr->rt_hdr.nexthdr = *prev_hdr;
526 *prev_hdr = NEXTHDR_ROUTING;
527 return &phdr->rt_hdr.nexthdr;
530 static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
532 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
534 memcpy(h, opt, ipv6_optlen(opt));
535 h->nexthdr = *prev_hdr;
536 *prev_hdr = type;
537 return &h->nexthdr;
540 static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
542 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
544 memcpy(h, opt, (opt->hdrlen+2)<<2);
545 h->nexthdr = *prev_hdr;
546 *prev_hdr = NEXTHDR_AUTH;
547 return &h->nexthdr;
551 u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
552 struct in6_addr *daddr, u32 jumbolen)
554 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
556 if (opt && opt->hopopt)
557 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
559 if (jumbolen) {
560 u8 *jumboopt = (u8 *)skb_put(skb, 8);
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;
574 jumboopt[0] = IPV6_TLV_JUMBO;
575 jumboopt[1] = 4;
576 *(u32*)(jumboopt+2) = htonl(jumbolen);
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);
584 return prev_hdr;
587 u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
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;
596 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
597 struct ipv6_rt_hdr *opt,
598 struct in6_addr **addr_p)
600 struct rt0_hdr *phdr, *ihdr;
601 int hops;
603 ihdr = (struct rt0_hdr *) opt;
605 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
606 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
608 hops = ihdr->rt_hdr.hdrlen >> 1;
610 if (hops > 1)
611 memcpy(phdr->addr, ihdr->addr + 1,
612 (hops - 1) * sizeof(struct in6_addr));
614 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
615 *addr_p = ihdr->addr;
617 phdr->rt_hdr.nexthdr = *proto;
618 *proto = NEXTHDR_ROUTING;
621 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
623 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
625 memcpy(h, opt, ipv6_optlen(opt));
626 h->nexthdr = *proto;
627 *proto = type;
630 static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
632 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
634 memcpy(h, opt, (opt->hdrlen+2)<<2);
635 h->nexthdr = *proto;
636 *proto = NEXTHDR_AUTH;
639 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
640 u8 *proto,
641 struct in6_addr **daddr)
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);
651 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
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);
659 struct ipv6_txoptions *
660 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
662 struct ipv6_txoptions *opt2;
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;
679 return opt2;
684 * find out if nexthdr is a well-known extension header or a protocol
687 static __inline__ int ipv6_ext_hdr(u8 nexthdr)
690 * find out if nexthdr is an extension header or a protocol
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) );
701 * Skip any extension headers. This is used by the ICMP module.
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.
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).
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
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.
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.
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.
739 * --ANK (980726)
742 u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len)
744 u8 nexthdr = *nexthdrp;
746 while (ipv6_ext_hdr(nexthdr)) {
747 int hdrlen;
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);
763 nexthdr = hdr->nexthdr;
764 hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen);
765 len -= hdrlen;
768 *nexthdrp = nexthdr;
769 return (u8*)hdr;