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