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