Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

exthdrs.c

Go to the documentation of this file.
00001 /*
00002  *      Extension Header handling for IPv6
00003  *      Linux INET6 implementation
00004  *
00005  *      Authors:
00006  *      Pedro Roque             <roque@di.fc.ul.pt>
00007  *      Andi Kleen              <ak@muc.de>
00008  *      Alexey Kuznetsov        <kuznet@ms2.inr.ac.ru>
00009  *
00010  *      $Id: exthdrs.c,v 1.8 1998/10/03 09:38:27 davem Exp $
00011  *
00012  *      This program is free software; you can redistribute it and/or
00013  *      modify it under the terms of the GNU General Public License
00014  *      as published by the Free Software Foundation; either version
00015  *      2 of the License, or (at your option) any later version.
00016  */
00017 
00018 #include <linux/errno.h>
00019 #include <linux/types.h>
00020 #include <linux/socket.h>
00021 #include <linux/sockios.h>
00022 #include <linux/sched.h>
00023 #include <linux/net.h>
00024 #include <linux/netdevice.h>
00025 #include <linux/in6.h>
00026 #include <linux/icmpv6.h>
00027 
00028 #include <net/sock.h>
00029 #include <net/snmp.h>
00030 
00031 #include <net/ipv6.h>
00032 #include <net/protocol.h>
00033 #include <net/transp_v6.h>
00034 #include <net/rawv6.h>
00035 #include <net/ndisc.h>
00036 #include <net/ip6_route.h>
00037 #include <net/addrconf.h>
00038 
00039 #include <asm/uaccess.h>
00040 
00041 /*
00042  *      Parsing inbound headers.
00043  *
00044  *      Parsing function "func" returns pointer to the place,
00045  *      where next nexthdr value is stored or NULL, if parsing
00046  *      failed. It should also update skb->h.
00047  */
00048 
00049 struct hdrtype_proc
00050 {
00051         int     type;
00052         u8*     (*func) (struct sk_buff **, u8 *ptr);
00053 };
00054 
00055 /*
00056  *      Parsing tlv encoded headers.
00057  *
00058  *      Parsing function "func" returns 1, if parsing succeed
00059  *      and 0, if it failed.
00060  *      It MUST NOT touch skb->h.
00061  */
00062 
00063 struct tlvtype_proc
00064 {
00065         int     type;
00066         int     (*func) (struct sk_buff *, __u8 *ptr);
00067 };
00068 
00069 /*********************
00070   Generic functions
00071  *********************/
00072 
00073 /* An unknown option is detected, decide what to do */
00074 
00075 int ip6_tlvopt_unknown(struct sk_buff *skb, u8 *opt)
00076 {
00077         switch ((opt[0] & 0xC0) >> 6) {
00078         case 0: /* ignore */
00079                 return 1;
00080                 
00081         case 1: /* drop packet */
00082                 break;
00083 
00084         case 3: /* Send ICMP if not a multicast address and drop packet */
00085                 /* Actually, it is redundant check. icmp_send
00086                    will recheck in any case.
00087                  */
00088                 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
00089                         break;
00090         case 2: /* send ICMP PARM PROB regardless and drop packet */
00091                 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, opt);
00092                 return 0;
00093         };
00094 
00095         kfree_skb(skb);
00096         return 0;
00097 }
00098 
00099 /* Parse tlv encoded option header (hop-by-hop or destination) */
00100 
00101 static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
00102                          __u8 *nhptr)
00103 {
00104         struct tlvtype_proc *curr;
00105         u8 *ptr = skb->h.raw;
00106         int len = ((ptr[1]+1)<<3) - 2;
00107 
00108         ptr += 2;
00109 
00110         if (skb->tail - (ptr + len) < 0) {
00111                 kfree_skb(skb);
00112                 return 0;
00113         }
00114 
00115         while (len > 0) {
00116                 int optlen = ptr[1]+2;
00117 
00118                 switch (ptr[0]) {
00119                 case IPV6_TLV_PAD0:
00120                         optlen = 1;
00121                         break;
00122 
00123                 case IPV6_TLV_PADN:
00124                         break;
00125 
00126                 default: /* Other TLV code so scan list */
00127                         for (curr=procs; curr->type >= 0; curr++) {
00128                                 if (curr->type == ptr[0]) {
00129                                         if (curr->func(skb, ptr) == 0)
00130                                                 return 0;
00131                                         break;
00132                                 }
00133                         }
00134                         if (curr->type < 0) {
00135                                 if (ip6_tlvopt_unknown(skb, ptr) == 0)
00136                                         return 0;
00137                         }
00138                         break;
00139                 }
00140                 ptr += optlen;
00141                 len -= optlen;
00142         }
00143         if (len == 0)
00144                 return 1;
00145         kfree_skb(skb);
00146         return 0;
00147 }
00148 
00149 /*****************************
00150   Destination options header.
00151  *****************************/
00152 
00153 struct tlvtype_proc tlvprocdestopt_lst[] = {
00154         /* No destination options are defined now */
00155         {-1,                    NULL}
00156 };
00157 
00158 static u8 *ipv6_dest_opt(struct sk_buff **skb_ptr, u8 *nhptr)
00159 {
00160         struct sk_buff *skb=*skb_ptr;
00161         struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
00162         struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
00163 
00164         opt->dst1 = (u8*)hdr - skb->nh.raw;
00165 
00166         if (ip6_parse_tlv(tlvprocdestopt_lst, skb, nhptr)) {
00167                 skb->h.raw += ((hdr->hdrlen+1)<<3);
00168                 return &hdr->nexthdr;
00169         }
00170 
00171         return NULL;
00172 }
00173 
00174 /********************************
00175   NONE header. No data in packet.
00176  ********************************/
00177 
00178 static u8 *ipv6_nodata(struct sk_buff **skb_ptr, u8 *nhptr)
00179 {
00180         kfree_skb(*skb_ptr);
00181         return NULL;
00182 }
00183 
00184 /********************************
00185   Routing header.
00186  ********************************/
00187 
00188 static u8* ipv6_routing_header(struct sk_buff **skb_ptr, u8 *nhptr)
00189 {
00190         struct sk_buff *skb = *skb_ptr;
00191         struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
00192         struct in6_addr *addr;
00193         struct in6_addr daddr;
00194         int addr_type;
00195         int n, i;
00196 
00197         struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw;
00198         struct rt0_hdr *rthdr;
00199 
00200         if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) {
00201                 ipv6_statistics.Ip6InHdrErrors++;
00202                 kfree_skb(skb);
00203                 return NULL;
00204         }
00205 
00206 looped_back:
00207         if (hdr->segments_left == 0) {
00208                 opt->srcrt = (u8*)hdr - skb->nh.raw;
00209                 skb->h.raw += (hdr->hdrlen + 1) << 3;
00210                 opt->dst0 = opt->dst1;
00211                 opt->dst1 = 0;
00212                 return &hdr->nexthdr;           
00213         }
00214 
00215         if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01) {
00216                 u8 *pos = (u8*) hdr;
00217 
00218                 if (hdr->type != IPV6_SRCRT_TYPE_0)
00219                         pos += 2;
00220                 else
00221                         pos += 1;
00222 
00223                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, pos);
00224                 return NULL;    
00225         }
00226         
00227         /*
00228          *      This is the routing header forwarding algorithm from
00229          *      RFC 1883, page 17.
00230          */
00231 
00232         n = hdr->hdrlen >> 1;
00233 
00234         if (hdr->segments_left > n) {
00235                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, &hdr->segments_left);
00236                 return NULL;
00237         }
00238 
00239         /* We are about to mangle packet header. Be careful!
00240            Do not damage packets queued somewhere.
00241          */
00242         if (skb_cloned(skb)) {
00243                 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
00244                 kfree_skb(skb);
00245                 if (skb2 == NULL)
00246                         return NULL;
00247                 *skb_ptr = skb = skb2;
00248                 opt = (struct inet6_skb_parm *)skb2->cb;
00249                 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
00250         }
00251 
00252         i = n - --hdr->segments_left;
00253 
00254         rthdr = (struct rt0_hdr *) hdr;
00255         addr = rthdr->addr;
00256         addr += i - 1;
00257 
00258         addr_type = ipv6_addr_type(addr);
00259 
00260         if (addr_type == IPV6_ADDR_MULTICAST) {
00261                 kfree_skb(skb);
00262                 return NULL;
00263         }
00264 
00265         ipv6_addr_copy(&daddr, addr);
00266         ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
00267         ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
00268 
00269         dst_release(xchg(&skb->dst, NULL));
00270         ip6_route_input(skb);
00271         if (skb->dst->error) {
00272                 skb->dst->input(skb);
00273                 return NULL;
00274         }
00275         if (skb->dst->dev->flags&IFF_LOOPBACK) {
00276                 if (skb->nh.ipv6h->hop_limit <= 1) {
00277                         icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
00278                                     0, skb->dev);
00279                         kfree_skb(skb);
00280                         return NULL;
00281                 }
00282                 skb->nh.ipv6h->hop_limit--;
00283                 goto looped_back;
00284         }
00285 
00286         skb->dst->input(skb);
00287         return NULL;
00288 }
00289 
00290 /*
00291    This function inverts received rthdr.
00292    NOTE: specs allow to make it automatically only if
00293    packet authenticated.
00294 
00295    I will not discuss it here (though, I am really pissed off at
00296    this stupid requirement making rthdr idea useless)
00297 
00298    Actually, it creates severe problems  for us.
00299    Embrionic requests has no associated sockets,
00300    so that user have no control over it and
00301    cannot not only to set reply options, but
00302    even to know, that someone wants to connect
00303    without success. :-(
00304 
00305    For now we need to test the engine, so that I created
00306    temporary (or permanent) backdoor.
00307    If listening socket set IPV6_RTHDR to 2, then we invert header.
00308                                                    --ANK (980729)
00309  */
00310 
00311 struct ipv6_txoptions *
00312 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
00313 {
00314         /* Received rthdr:
00315 
00316            [ H1 -> H2 -> ... H_prev ]  daddr=ME
00317 
00318            Inverted result:
00319            [ H_prev -> ... -> H1 ] daddr =sender
00320 
00321            Note, that IP output engine will rewrire this rthdr
00322            by rotating it left by one addr.
00323          */
00324 
00325         int n, i;
00326         struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
00327         struct rt0_hdr *irthdr;
00328         struct ipv6_txoptions *opt;
00329         int hdrlen = ipv6_optlen(hdr);
00330 
00331         if (hdr->segments_left ||
00332             hdr->type != IPV6_SRCRT_TYPE_0 ||
00333             hdr->hdrlen & 0x01)
00334                 return NULL;
00335 
00336         n = hdr->hdrlen >> 1;
00337         opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
00338         if (opt == NULL)
00339                 return NULL;
00340         memset(opt, 0, sizeof(*opt));
00341         opt->tot_len = sizeof(*opt) + hdrlen;
00342         opt->srcrt = (void*)(opt+1);
00343         opt->opt_nflen = hdrlen;
00344 
00345         memcpy(opt->srcrt, hdr, sizeof(*hdr));
00346         irthdr = (struct rt0_hdr*)opt->srcrt;
00347         /* Obsolete field, MBZ, when originated by us */
00348         irthdr->bitmap = 0;
00349         opt->srcrt->segments_left = n;
00350         for (i=0; i<n; i++)
00351                 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
00352         return opt;
00353 }
00354 
00355 /********************************
00356   AUTH header.
00357  ********************************/
00358 
00359 /*
00360    rfc1826 said, that if a host does not implement AUTH header
00361    it MAY ignore it. We use this hole 8)
00362 
00363    Actually, now we can implement OSPFv6 without kernel IPsec.
00364    Authentication for poors may be done in user space with the same success.
00365 
00366    Yes, it means, that we allow application to send/receive
00367    raw authentication header. Apparently, we suppose, that it knows
00368    what it does and calculates authentication data correctly.
00369    Certainly, it is possible only for udp and raw sockets, but not for tcp.
00370 
00371    AUTH header has 4byte granular length, which kills all the idea
00372    behind AUTOMATIC 64bit alignment of IPv6. Now we will loose
00373    cpu ticks, checking that sender did not something stupid
00374    and opt->hdrlen is even. Shit!               --ANK (980730)
00375  */
00376 
00377 static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr)
00378 {
00379         struct sk_buff *skb=*skb_ptr;
00380         struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
00381         struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw;
00382         int len = (hdr->hdrlen+2)<<2;
00383 
00384         if (len&7)
00385                 return NULL;
00386         opt->auth = (u8*)hdr - skb->nh.raw;
00387         if (skb->h.raw + len > skb->tail)
00388                 return NULL;
00389         skb->h.raw += len;
00390         return &hdr->nexthdr;
00391 }
00392 
00393 /* This list MUST NOT contain entry for NEXTHDR_HOP.
00394    It is parsed immediately after packet received
00395    and if it occurs somewhere in another place we must
00396    generate error.
00397  */
00398 
00399 struct hdrtype_proc hdrproc_lst[] = {
00400         {NEXTHDR_FRAGMENT,      ipv6_reassembly},
00401         {NEXTHDR_ROUTING,       ipv6_routing_header},
00402         {NEXTHDR_DEST,          ipv6_dest_opt},
00403         {NEXTHDR_NONE,          ipv6_nodata},
00404         {NEXTHDR_AUTH,          ipv6_auth_hdr},
00405    /*
00406         {NEXTHDR_ESP,           ipv6_esp_hdr},
00407     */
00408         {-1,                    NULL}
00409 };
00410 
00411 u8 *ipv6_parse_exthdrs(struct sk_buff **skb_in, u8 *nhptr)
00412 {
00413         struct hdrtype_proc *hdrt;
00414         u8 nexthdr = *nhptr;
00415 
00416 restart:
00417         for (hdrt=hdrproc_lst; hdrt->type >= 0; hdrt++) {
00418                 if (hdrt->type == nexthdr) {
00419                         if ((nhptr = hdrt->func(skb_in, nhptr)) != NULL) {
00420                                 nexthdr = *nhptr;
00421                                 goto restart;
00422                         }
00423                         return NULL;
00424                 }
00425         }
00426         return nhptr;
00427 }
00428 
00429 
00430 /**********************************
00431   Hop-by-hop options.
00432  **********************************/
00433 
00434 /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
00435 
00436 static int ipv6_hop_ra(struct sk_buff *skb, u8 *ptr)
00437 {
00438         if (ptr[1] == 2) {
00439                 ((struct inet6_skb_parm*)skb->cb)->ra = ptr - skb->nh.raw;
00440                 return 1;
00441         }
00442         if (net_ratelimit())
00443                 printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", ptr[1]);
00444         kfree_skb(skb);
00445         return 0;
00446 }
00447 
00448 /* Jumbo payload */
00449 
00450 static int ipv6_hop_jumbo(struct sk_buff *skb, u8 *ptr)
00451 {
00452         u32 pkt_len;
00453 
00454         if (ptr[1] != 4 || ((ptr-skb->nh.raw)&3) != 2) {
00455                 if (net_ratelimit())
00456                         printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", ptr[1]);
00457                 goto drop;
00458         }
00459 
00460         pkt_len = ntohl(*(u32*)(ptr+2));
00461         if (pkt_len < 0x10000) {
00462                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr+2);
00463                 return 0;
00464         }
00465         if (skb->nh.ipv6h->payload_len) {
00466                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, ptr);
00467                 return 0;
00468         }
00469 
00470         if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
00471                 ipv6_statistics.Ip6InTruncatedPkts++;
00472                 goto drop;
00473         }
00474         skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
00475         return 1;
00476 
00477 drop:
00478         kfree_skb(skb);
00479         return 0;
00480 }
00481 
00482 struct tlvtype_proc tlvprochopopt_lst[] = {
00483         {IPV6_TLV_ROUTERALERT,  ipv6_hop_ra},
00484         {IPV6_TLV_JUMBO,        ipv6_hop_jumbo},
00485         {-1,                    NULL}
00486 };
00487 
00488 u8 * ipv6_parse_hopopts(struct sk_buff *skb, u8 *nhptr)
00489 {
00490         ((struct inet6_skb_parm*)skb->cb)->hop = sizeof(struct ipv6hdr);
00491         if (ip6_parse_tlv(tlvprochopopt_lst, skb, nhptr))
00492                 return nhptr+((nhptr[1]+1)<<3);
00493         return NULL;
00494 }
00495 
00496 /*
00497  *      Creating outbound headers.
00498  *
00499  *      "build" functions work when skb is filled from head to tail (datagram)
00500  *      "push"  functions work when headers are added from tail to head (tcp)
00501  *
00502  *      In both cases we assume, that caller reserved enough room
00503  *      for headers.
00504  */
00505 
00506 u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
00507                      struct ipv6_rt_hdr *opt, struct in6_addr *addr)
00508 {
00509         struct rt0_hdr *phdr, *ihdr;
00510         int hops;
00511 
00512         ihdr = (struct rt0_hdr *) opt;
00513         
00514         phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
00515         memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
00516 
00517         hops = ihdr->rt_hdr.hdrlen >> 1;
00518 
00519         if (hops > 1)
00520                 memcpy(phdr->addr, ihdr->addr + 1,
00521                        (hops - 1) * sizeof(struct in6_addr));
00522 
00523         ipv6_addr_copy(phdr->addr + (hops - 1), addr);
00524 
00525         phdr->rt_hdr.nexthdr = *prev_hdr;
00526         *prev_hdr = NEXTHDR_ROUTING;
00527         return &phdr->rt_hdr.nexthdr;
00528 }
00529 
00530 static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
00531 {
00532         struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
00533 
00534         memcpy(h, opt, ipv6_optlen(opt));
00535         h->nexthdr = *prev_hdr;
00536         *prev_hdr = type;
00537         return &h->nexthdr;
00538 }
00539 
00540 static u8 *ipv6_build_authhdr(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_opt_hdr *opt)
00541 {
00542         struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, (opt->hdrlen+2)<<2);
00543 
00544         memcpy(h, opt, (opt->hdrlen+2)<<2);
00545         h->nexthdr = *prev_hdr;
00546         *prev_hdr = NEXTHDR_AUTH;
00547         return &h->nexthdr;
00548 }
00549 
00550 
00551 u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
00552                           struct in6_addr *daddr, u32 jumbolen)
00553 {
00554         struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
00555 
00556         if (opt && opt->hopopt)
00557                 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
00558 
00559         if (jumbolen) {
00560                 u8 *jumboopt = (u8 *)skb_put(skb, 8);
00561 
00562                 if (opt && opt->hopopt) {
00563                         *jumboopt++ = IPV6_TLV_PADN;
00564                         *jumboopt++ = 0;
00565                         h->hdrlen++;
00566                 } else {
00567                         h = (struct ipv6_opt_hdr *)jumboopt;
00568                         h->nexthdr = *prev_hdr;
00569                         h->hdrlen = 0;
00570                         jumboopt += 2;
00571                         *prev_hdr = NEXTHDR_HOP;
00572                         prev_hdr = &h->nexthdr;
00573                 }
00574                 jumboopt[0] = IPV6_TLV_JUMBO;
00575                 jumboopt[1] = 4;
00576                 *(u32*)(jumboopt+2) = htonl(jumbolen);
00577         }
00578         if (opt) {
00579                 if (opt->dst0opt)
00580                         prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
00581                 if (opt->srcrt)
00582                         prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
00583         }
00584         return prev_hdr;
00585 }
00586 
00587 u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
00588 {
00589         if (opt->auth)
00590                 prev_hdr = ipv6_build_authhdr(skb, prev_hdr, opt->auth);
00591         if (opt->dst1opt)
00592                 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
00593         return prev_hdr;
00594 }
00595 
00596 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
00597                             struct ipv6_rt_hdr *opt,
00598                             struct in6_addr **addr_p)
00599 {
00600         struct rt0_hdr *phdr, *ihdr;
00601         int hops;
00602 
00603         ihdr = (struct rt0_hdr *) opt;
00604         
00605         phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
00606         memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
00607 
00608         hops = ihdr->rt_hdr.hdrlen >> 1;
00609 
00610         if (hops > 1)
00611                 memcpy(phdr->addr, ihdr->addr + 1,
00612                        (hops - 1) * sizeof(struct in6_addr));
00613 
00614         ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
00615         *addr_p = ihdr->addr;
00616 
00617         phdr->rt_hdr.nexthdr = *proto;
00618         *proto = NEXTHDR_ROUTING;
00619 }
00620 
00621 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
00622 {
00623         struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
00624 
00625         memcpy(h, opt, ipv6_optlen(opt));
00626         h->nexthdr = *proto;
00627         *proto = type;
00628 }
00629 
00630 static void ipv6_push_authhdr(struct sk_buff *skb, u8 *proto, struct ipv6_opt_hdr *opt)
00631 {
00632         struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, (opt->hdrlen+2)<<2);
00633 
00634         memcpy(h, opt, (opt->hdrlen+2)<<2);
00635         h->nexthdr = *proto;
00636         *proto = NEXTHDR_AUTH;
00637 }
00638 
00639 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
00640                           u8 *proto,
00641                           struct in6_addr **daddr)
00642 {
00643         if (opt->srcrt)
00644                 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
00645         if (opt->dst0opt)
00646                 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
00647         if (opt->hopopt)
00648                 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
00649 }
00650 
00651 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
00652 {
00653         if (opt->dst1opt)
00654                 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
00655         if (opt->auth)
00656                 ipv6_push_authhdr(skb, proto, opt->auth);
00657 }
00658 
00659 struct ipv6_txoptions *
00660 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
00661 {
00662         struct ipv6_txoptions *opt2;
00663 
00664         opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
00665         if (opt2) {
00666                 long dif = (char*)opt2 - (char*)opt;
00667                 memcpy(opt2, opt, opt->tot_len);
00668                 if (opt2->hopopt)
00669                         *((char**)&opt2->hopopt) += dif;
00670                 if (opt2->dst0opt)
00671                         *((char**)&opt2->dst0opt) += dif;
00672                 if (opt2->dst1opt)
00673                         *((char**)&opt2->dst1opt) += dif;
00674                 if (opt2->auth)
00675                         *((char**)&opt2->auth) += dif;
00676                 if (opt2->srcrt)
00677                         *((char**)&opt2->srcrt) += dif;
00678         }
00679         return opt2;
00680 }
00681 
00682 
00683 /* 
00684  * find out if nexthdr is a well-known extension header or a protocol
00685  */
00686 
00687 static __inline__ int ipv6_ext_hdr(u8 nexthdr)
00688 {
00689         /* 
00690          * find out if nexthdr is an extension header or a protocol
00691          */
00692         return ( (nexthdr == NEXTHDR_HOP)       ||
00693                  (nexthdr == NEXTHDR_ROUTING)   ||
00694                  (nexthdr == NEXTHDR_FRAGMENT)  ||
00695                  (nexthdr == NEXTHDR_AUTH)      ||
00696                  (nexthdr == NEXTHDR_NONE)      ||
00697                  (nexthdr == NEXTHDR_DEST) );
00698 }
00699 
00700 /*
00701  * Skip any extension headers. This is used by the ICMP module.
00702  *
00703  * Note that strictly speaking this conflicts with RFC1883 4.0:
00704  * ...The contents and semantics of each extension header determine whether 
00705  * or not to proceed to the next header.  Therefore, extension headers must
00706  * be processed strictly in the order they appear in the packet; a
00707  * receiver must not, for example, scan through a packet looking for a
00708  * particular kind of extension header and process that header prior to
00709  * processing all preceding ones.
00710  * 
00711  * We do exactly this. This is a protocol bug. We can't decide after a
00712  * seeing an unknown discard-with-error flavour TLV option if it's a 
00713  * ICMP error message or not (errors should never be send in reply to
00714  * ICMP error messages).
00715  * 
00716  * But I see no other way to do this. This might need to be reexamined
00717  * when Linux implements ESP (and maybe AUTH) headers.
00718  * --AK
00719  *
00720  * This function parses (probably truncated) exthdr set "hdr"
00721  * of length "len". "nexthdrp" initially points to some place,
00722  * where type of the first header can be found.
00723  *
00724  * It skips all well-known exthdrs, and returns pointer to the start
00725  * of unparsable area i.e. the first header with unknown type.
00726  * If it is not NULL *nexthdr is updated by type/protocol of this header.
00727  *
00728  * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
00729  *        - it may return pointer pointing beyond end of packet,
00730  *          if the last recognized header is truncated in the middle.
00731  *        - if packet is truncated, so that all parsed headers are skipped,
00732  *          it returns NULL.
00733  *        - First fragment header is skipped, not-first ones
00734  *          are considered as unparsable.
00735  *        - ESP is unparsable for now and considered like
00736  *          normal payload protocol.
00737  *        - Note also special handling of AUTH header. Thanks to IPsec wizards.
00738  *
00739  * --ANK (980726)
00740  */
00741 
00742 u8 *ipv6_skip_exthdr(struct ipv6_opt_hdr *hdr, u8 *nexthdrp, int len)
00743 {
00744         u8 nexthdr = *nexthdrp;
00745 
00746         while (ipv6_ext_hdr(nexthdr)) {
00747                 int hdrlen; 
00748 
00749                 if (len < sizeof(struct ipv6_opt_hdr))
00750                         return NULL;
00751                 if (nexthdr == NEXTHDR_NONE)
00752                         return NULL;
00753                 if (nexthdr == NEXTHDR_FRAGMENT) {
00754                         struct frag_hdr *fhdr = (struct frag_hdr *) hdr;
00755                         if (ntohs(fhdr->frag_off) & ~0x7)
00756                                 break;
00757                         hdrlen = 8;
00758                 } else if (nexthdr == NEXTHDR_AUTH)
00759                         hdrlen = (hdr->hdrlen+2)<<2; 
00760                 else
00761                         hdrlen = ipv6_optlen(hdr); 
00762 
00763                 nexthdr = hdr->nexthdr;
00764                 hdr = (struct ipv6_opt_hdr *) ((u8*)hdr + hdrlen);
00765                 len -= hdrlen;
00766         }
00767 
00768         *nexthdrp = nexthdr;
00769         return (u8*)hdr;
00770 }
00771