~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipv6/exthdrs.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.