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