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