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