2 * Extension Header handling for IPv6
3 * Linux INET6 implementation
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Andi Kleen <ak@muc.de>
8 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
10 * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $
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.
19 * yoshfuji : ensure not to overrun while parsing
21 * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
22 * YOSHIFUJI Hideaki @USAGI Register inbound extension header
23 * handlers as inet6_protocol{}.
26 #include <linux/errno.h>
27 #include <linux/types.h>
28 #include <linux/socket.h>
29 #include <linux/sockios.h>
30 #include <linux/net.h>
31 #include <linux/netdevice.h>
32 #include <linux/in6.h>
33 #include <linux/icmpv6.h>
39 #include <net/protocol.h>
40 #include <net/transp_v6.h>
41 #include <net/rawv6.h>
42 #include <net/ndisc.h>
43 #include <net/ip6_route.h>
44 #include <net/addrconf.h>
45 #ifdef CONFIG_IPV6_MIP6
49 #include <asm/uaccess.h>
51 int ipv6_find_tlv(struct sk_buff
*skb
, int offset
, int type
)
53 int packet_len
= skb
->tail
- skb
->nh
.raw
;
54 struct ipv6_opt_hdr
*hdr
;
57 if (offset
+ 2 > packet_len
)
59 hdr
= (struct ipv6_opt_hdr
*)(skb
->nh
.raw
+ offset
);
60 len
= ((hdr
->hdrlen
+ 1) << 3);
62 if (offset
+ len
> packet_len
)
69 int opttype
= skb
->nh
.raw
[offset
];
80 optlen
= skb
->nh
.raw
[offset
+ 1] + 2;
94 * Parsing tlv encoded headers.
96 * Parsing function "func" returns 1, if parsing succeed
97 * and 0, if it failed.
98 * It MUST NOT touch skb->h.
101 struct tlvtype_proc
{
103 int (*func
)(struct sk_buff
**skbp
, int offset
);
106 /*********************
108 *********************/
110 /* An unknown option is detected, decide what to do */
112 static int ip6_tlvopt_unknown(struct sk_buff
**skbp
, int optoff
)
114 struct sk_buff
*skb
= *skbp
;
116 switch ((skb
->nh
.raw
[optoff
] & 0xC0) >> 6) {
120 case 1: /* drop packet */
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.
127 if (ipv6_addr_is_multicast(&skb
->nh
.ipv6h
->daddr
))
129 case 2: /* send ICMP PARM PROB regardless and drop packet */
130 icmpv6_param_prob(skb
, ICMPV6_UNK_OPTION
, optoff
);
138 /* Parse tlv encoded option header (hop-by-hop or destination) */
140 static int ip6_parse_tlv(struct tlvtype_proc
*procs
, struct sk_buff
**skbp
)
142 struct sk_buff
*skb
= *skbp
;
143 struct tlvtype_proc
*curr
;
144 int off
= skb
->h
.raw
- skb
->nh
.raw
;
145 int len
= ((skb
->h
.raw
[1]+1)<<3);
147 if ((skb
->h
.raw
+ len
) - skb
->data
> skb_headlen(skb
))
154 int optlen
= skb
->nh
.raw
[off
+1]+2;
156 switch (skb
->nh
.raw
[off
]) {
164 default: /* Other TLV code so scan list */
167 for (curr
=procs
; curr
->type
>= 0; curr
++) {
168 if (curr
->type
== skb
->nh
.raw
[off
]) {
169 /* type specific length/alignment
170 checks will be performed in the
172 if (curr
->func(skbp
, off
) == 0)
177 if (curr
->type
< 0) {
178 if (ip6_tlvopt_unknown(skbp
, off
) == 0)
193 /*****************************
194 Destination options header.
195 *****************************/
197 #ifdef CONFIG_IPV6_MIP6
198 static int ipv6_dest_hao(struct sk_buff
**skbp
, int optoff
)
200 struct sk_buff
*skb
= *skbp
;
201 struct ipv6_destopt_hao
*hao
;
202 struct inet6_skb_parm
*opt
= IP6CB(skb
);
203 struct ipv6hdr
*ipv6h
= (struct ipv6hdr
*)skb
->nh
.raw
;
204 struct in6_addr tmp_addr
;
208 LIMIT_NETDEBUG(KERN_DEBUG
"hao duplicated\n");
211 opt
->dsthao
= opt
->dst1
;
214 hao
= (struct ipv6_destopt_hao
*)(skb
->nh
.raw
+ optoff
);
216 if (hao
->length
!= 16) {
218 KERN_DEBUG
"hao invalid option length = %d\n", hao
->length
);
222 if (!(ipv6_addr_type(&hao
->addr
) & IPV6_ADDR_UNICAST
)) {
224 KERN_DEBUG
"hao is not an unicast addr: " NIP6_FMT
"\n", NIP6(hao
->addr
));
228 ret
= xfrm6_input_addr(skb
, (xfrm_address_t
*)&ipv6h
->daddr
,
229 (xfrm_address_t
*)&hao
->addr
, IPPROTO_DSTOPTS
);
230 if (unlikely(ret
< 0))
233 if (skb_cloned(skb
)) {
234 struct sk_buff
*skb2
= skb_copy(skb
, GFP_ATOMIC
);
235 struct inet6_skb_parm
*opt2
;
241 memcpy(opt2
, opt
, sizeof(*opt2
));
245 /* update all variable using below by copied skbuff */
247 hao
= (struct ipv6_destopt_hao
*)(skb2
->nh
.raw
+ optoff
);
248 ipv6h
= (struct ipv6hdr
*)skb2
->nh
.raw
;
251 if (skb
->ip_summed
== CHECKSUM_COMPLETE
)
252 skb
->ip_summed
= CHECKSUM_NONE
;
254 ipv6_addr_copy(&tmp_addr
, &ipv6h
->saddr
);
255 ipv6_addr_copy(&ipv6h
->saddr
, &hao
->addr
);
256 ipv6_addr_copy(&hao
->addr
, &tmp_addr
);
258 if (skb
->tstamp
.off_sec
== 0)
259 __net_timestamp(skb
);
269 static struct tlvtype_proc tlvprocdestopt_lst
[] = {
270 #ifdef CONFIG_IPV6_MIP6
272 .type
= IPV6_TLV_HAO
,
273 .func
= ipv6_dest_hao
,
279 static int ipv6_destopt_rcv(struct sk_buff
**skbp
)
281 struct sk_buff
*skb
= *skbp
;
282 struct inet6_skb_parm
*opt
= IP6CB(skb
);
283 #ifdef CONFIG_IPV6_MIP6
286 struct dst_entry
*dst
;
288 if (!pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+8) ||
289 !pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+((skb
->h
.raw
[1]+1)<<3))) {
290 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
291 IPSTATS_MIB_INHDRERRORS
);
296 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
297 opt
->dst1
= skb
->h
.raw
- skb
->nh
.raw
;
298 #ifdef CONFIG_IPV6_MIP6
302 dst
= dst_clone(skb
->dst
);
303 if (ip6_parse_tlv(tlvprocdestopt_lst
, skbp
)) {
306 skb
->h
.raw
+= ((skb
->h
.raw
[1]+1)<<3);
308 #ifdef CONFIG_IPV6_MIP6
311 opt
->nhoff
= opt
->dst1
;
316 IP6_INC_STATS_BH(ip6_dst_idev(dst
), IPSTATS_MIB_INHDRERRORS
);
321 static struct inet6_protocol destopt_protocol
= {
322 .handler
= ipv6_destopt_rcv
,
323 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
326 void __init
ipv6_destopt_init(void)
328 if (inet6_add_protocol(&destopt_protocol
, IPPROTO_DSTOPTS
) < 0)
329 printk(KERN_ERR
"ipv6_destopt_init: Could not register protocol\n");
332 /********************************
333 NONE header. No data in packet.
334 ********************************/
336 static int ipv6_nodata_rcv(struct sk_buff
**skbp
)
338 struct sk_buff
*skb
= *skbp
;
344 static struct inet6_protocol nodata_protocol
= {
345 .handler
= ipv6_nodata_rcv
,
346 .flags
= INET6_PROTO_NOPOLICY
,
349 void __init
ipv6_nodata_init(void)
351 if (inet6_add_protocol(&nodata_protocol
, IPPROTO_NONE
) < 0)
352 printk(KERN_ERR
"ipv6_nodata_init: Could not register protocol\n");
355 /********************************
357 ********************************/
359 static int ipv6_rthdr_rcv(struct sk_buff
**skbp
)
361 struct sk_buff
*skb
= *skbp
;
362 struct inet6_skb_parm
*opt
= IP6CB(skb
);
363 struct in6_addr
*addr
= NULL
;
364 struct in6_addr daddr
;
365 struct inet6_dev
*idev
;
367 struct ipv6_rt_hdr
*hdr
;
368 struct rt0_hdr
*rthdr
;
369 int accept_source_route
= ipv6_devconf
.accept_source_route
;
371 if (accept_source_route
< 0 ||
372 ((idev
= in6_dev_get(skb
->dev
)) == NULL
)) {
376 if (idev
->cnf
.accept_source_route
< 0) {
382 if (accept_source_route
> idev
->cnf
.accept_source_route
)
383 accept_source_route
= idev
->cnf
.accept_source_route
;
387 if (!pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+8) ||
388 !pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+((skb
->h
.raw
[1]+1)<<3))) {
389 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
390 IPSTATS_MIB_INHDRERRORS
);
395 hdr
= (struct ipv6_rt_hdr
*) skb
->h
.raw
;
398 #ifdef CONFIG_IPV6_MIP6
401 case IPV6_SRCRT_TYPE_0
:
402 if (accept_source_route
> 0)
407 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
408 IPSTATS_MIB_INHDRERRORS
);
409 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->type
) - skb
->nh
.raw
);
413 if (ipv6_addr_is_multicast(&skb
->nh
.ipv6h
->daddr
) ||
414 skb
->pkt_type
!= PACKET_HOST
) {
415 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
416 IPSTATS_MIB_INADDRERRORS
);
422 if (hdr
->segments_left
== 0) {
424 #ifdef CONFIG_IPV6_MIP6
425 case IPV6_SRCRT_TYPE_2
:
426 /* Silently discard type 2 header unless it was
430 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
431 IPSTATS_MIB_INADDRERRORS
);
441 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
442 opt
->srcrt
= skb
->h
.raw
- skb
->nh
.raw
;
443 skb
->h
.raw
+= (hdr
->hdrlen
+ 1) << 3;
444 opt
->dst0
= opt
->dst1
;
446 opt
->nhoff
= (&hdr
->nexthdr
) - skb
->nh
.raw
;
451 case IPV6_SRCRT_TYPE_0
:
452 if (hdr
->hdrlen
& 0x01) {
453 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
454 IPSTATS_MIB_INHDRERRORS
);
455 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->hdrlen
) - skb
->nh
.raw
);
459 #ifdef CONFIG_IPV6_MIP6
460 case IPV6_SRCRT_TYPE_2
:
461 /* Silently discard invalid RTH type 2 */
462 if (hdr
->hdrlen
!= 2 || hdr
->segments_left
!= 1) {
463 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
464 IPSTATS_MIB_INHDRERRORS
);
473 * This is the routing header forwarding algorithm from
477 n
= hdr
->hdrlen
>> 1;
479 if (hdr
->segments_left
> n
) {
480 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
481 IPSTATS_MIB_INHDRERRORS
);
482 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->segments_left
) - skb
->nh
.raw
);
486 /* We are about to mangle packet header. Be careful!
487 Do not damage packets queued somewhere.
489 if (skb_cloned(skb
)) {
490 struct sk_buff
*skb2
= skb_copy(skb
, GFP_ATOMIC
);
491 /* the copy is a forwarded packet */
493 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
494 IPSTATS_MIB_OUTDISCARDS
);
501 hdr
= (struct ipv6_rt_hdr
*) skb2
->h
.raw
;
504 if (skb
->ip_summed
== CHECKSUM_COMPLETE
)
505 skb
->ip_summed
= CHECKSUM_NONE
;
507 i
= n
- --hdr
->segments_left
;
509 rthdr
= (struct rt0_hdr
*) hdr
;
514 #ifdef CONFIG_IPV6_MIP6
515 case IPV6_SRCRT_TYPE_2
:
516 if (xfrm6_input_addr(skb
, (xfrm_address_t
*)addr
,
517 (xfrm_address_t
*)&skb
->nh
.ipv6h
->saddr
,
518 IPPROTO_ROUTING
) < 0) {
519 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
520 IPSTATS_MIB_INADDRERRORS
);
524 if (!ipv6_chk_home_addr(addr
)) {
525 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
526 IPSTATS_MIB_INADDRERRORS
);
536 if (ipv6_addr_is_multicast(addr
)) {
537 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
538 IPSTATS_MIB_INADDRERRORS
);
543 ipv6_addr_copy(&daddr
, addr
);
544 ipv6_addr_copy(addr
, &skb
->nh
.ipv6h
->daddr
);
545 ipv6_addr_copy(&skb
->nh
.ipv6h
->daddr
, &daddr
);
547 dst_release(xchg(&skb
->dst
, NULL
));
548 ip6_route_input(skb
);
549 if (skb
->dst
->error
) {
550 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
555 if (skb
->dst
->dev
->flags
&IFF_LOOPBACK
) {
556 if (skb
->nh
.ipv6h
->hop_limit
<= 1) {
557 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
558 IPSTATS_MIB_INHDRERRORS
);
559 icmpv6_send(skb
, ICMPV6_TIME_EXCEED
, ICMPV6_EXC_HOPLIMIT
,
564 skb
->nh
.ipv6h
->hop_limit
--;
568 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
573 static struct inet6_protocol rthdr_protocol
= {
574 .handler
= ipv6_rthdr_rcv
,
575 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
578 void __init
ipv6_rthdr_init(void)
580 if (inet6_add_protocol(&rthdr_protocol
, IPPROTO_ROUTING
) < 0)
581 printk(KERN_ERR
"ipv6_rthdr_init: Could not register protocol\n");
585 This function inverts received rthdr.
586 NOTE: specs allow to make it automatically only if
587 packet authenticated.
589 I will not discuss it here (though, I am really pissed off at
590 this stupid requirement making rthdr idea useless)
592 Actually, it creates severe problems for us.
593 Embryonic requests has no associated sockets,
594 so that user have no control over it and
595 cannot not only to set reply options, but
596 even to know, that someone wants to connect
599 For now we need to test the engine, so that I created
600 temporary (or permanent) backdoor.
601 If listening socket set IPV6_RTHDR to 2, then we invert header.
605 struct ipv6_txoptions
*
606 ipv6_invert_rthdr(struct sock
*sk
, struct ipv6_rt_hdr
*hdr
)
610 [ H1 -> H2 -> ... H_prev ] daddr=ME
613 [ H_prev -> ... -> H1 ] daddr =sender
615 Note, that IP output engine will rewrite this rthdr
616 by rotating it left by one addr.
620 struct rt0_hdr
*rthdr
= (struct rt0_hdr
*)hdr
;
621 struct rt0_hdr
*irthdr
;
622 struct ipv6_txoptions
*opt
;
623 int hdrlen
= ipv6_optlen(hdr
);
625 if (hdr
->segments_left
||
626 hdr
->type
!= IPV6_SRCRT_TYPE_0
||
630 n
= hdr
->hdrlen
>> 1;
631 opt
= sock_kmalloc(sk
, sizeof(*opt
) + hdrlen
, GFP_ATOMIC
);
634 memset(opt
, 0, sizeof(*opt
));
635 opt
->tot_len
= sizeof(*opt
) + hdrlen
;
636 opt
->srcrt
= (void*)(opt
+1);
637 opt
->opt_nflen
= hdrlen
;
639 memcpy(opt
->srcrt
, hdr
, sizeof(*hdr
));
640 irthdr
= (struct rt0_hdr
*)opt
->srcrt
;
641 irthdr
->reserved
= 0;
642 opt
->srcrt
->segments_left
= n
;
644 memcpy(irthdr
->addr
+i
, rthdr
->addr
+(n
-1-i
), 16);
648 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr
);
650 /**********************************
652 **********************************/
654 /* Router Alert as of RFC 2711 */
656 static int ipv6_hop_ra(struct sk_buff
**skbp
, int optoff
)
658 struct sk_buff
*skb
= *skbp
;
660 if (skb
->nh
.raw
[optoff
+1] == 2) {
661 IP6CB(skb
)->ra
= optoff
;
664 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_ra: wrong RA length %d\n",
665 skb
->nh
.raw
[optoff
+1]);
672 static int ipv6_hop_jumbo(struct sk_buff
**skbp
, int optoff
)
674 struct sk_buff
*skb
= *skbp
;
677 if (skb
->nh
.raw
[optoff
+1] != 4 || (optoff
&3) != 2) {
678 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
679 skb
->nh
.raw
[optoff
+1]);
680 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
681 IPSTATS_MIB_INHDRERRORS
);
685 pkt_len
= ntohl(*(__be32
*)(skb
->nh
.raw
+optoff
+2));
686 if (pkt_len
<= IPV6_MAXPLEN
) {
687 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
), IPSTATS_MIB_INHDRERRORS
);
688 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
+2);
691 if (skb
->nh
.ipv6h
->payload_len
) {
692 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
), IPSTATS_MIB_INHDRERRORS
);
693 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
);
697 if (pkt_len
> skb
->len
- sizeof(struct ipv6hdr
)) {
698 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
), IPSTATS_MIB_INTRUNCATEDPKTS
);
702 if (pskb_trim_rcsum(skb
, pkt_len
+ sizeof(struct ipv6hdr
)))
712 static struct tlvtype_proc tlvprochopopt_lst
[] = {
714 .type
= IPV6_TLV_ROUTERALERT
,
718 .type
= IPV6_TLV_JUMBO
,
719 .func
= ipv6_hop_jumbo
,
724 int ipv6_parse_hopopts(struct sk_buff
**skbp
)
726 struct sk_buff
*skb
= *skbp
;
727 struct inet6_skb_parm
*opt
= IP6CB(skb
);
730 * skb->nh.raw is equal to skb->data, and
731 * skb->h.raw - skb->nh.raw is always equal to
732 * sizeof(struct ipv6hdr) by definition of
733 * hop-by-hop options.
735 if (!pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + 8) ||
736 !pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + ((skb
->h
.raw
[1] + 1) << 3))) {
741 opt
->hop
= sizeof(struct ipv6hdr
);
742 if (ip6_parse_tlv(tlvprochopopt_lst
, skbp
)) {
744 skb
->h
.raw
+= (skb
->h
.raw
[1]+1)<<3;
746 opt
->nhoff
= sizeof(struct ipv6hdr
);
753 * Creating outbound headers.
755 * "build" functions work when skb is filled from head to tail (datagram)
756 * "push" functions work when headers are added from tail to head (tcp)
758 * In both cases we assume, that caller reserved enough room
762 static void ipv6_push_rthdr(struct sk_buff
*skb
, u8
*proto
,
763 struct ipv6_rt_hdr
*opt
,
764 struct in6_addr
**addr_p
)
766 struct rt0_hdr
*phdr
, *ihdr
;
769 ihdr
= (struct rt0_hdr
*) opt
;
771 phdr
= (struct rt0_hdr
*) skb_push(skb
, (ihdr
->rt_hdr
.hdrlen
+ 1) << 3);
772 memcpy(phdr
, ihdr
, sizeof(struct rt0_hdr
));
774 hops
= ihdr
->rt_hdr
.hdrlen
>> 1;
777 memcpy(phdr
->addr
, ihdr
->addr
+ 1,
778 (hops
- 1) * sizeof(struct in6_addr
));
780 ipv6_addr_copy(phdr
->addr
+ (hops
- 1), *addr_p
);
781 *addr_p
= ihdr
->addr
;
783 phdr
->rt_hdr
.nexthdr
= *proto
;
784 *proto
= NEXTHDR_ROUTING
;
787 static void ipv6_push_exthdr(struct sk_buff
*skb
, u8
*proto
, u8 type
, struct ipv6_opt_hdr
*opt
)
789 struct ipv6_opt_hdr
*h
= (struct ipv6_opt_hdr
*)skb_push(skb
, ipv6_optlen(opt
));
791 memcpy(h
, opt
, ipv6_optlen(opt
));
796 void ipv6_push_nfrag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
,
798 struct in6_addr
**daddr
)
801 ipv6_push_rthdr(skb
, proto
, opt
->srcrt
, daddr
);
803 * IPV6_RTHDRDSTOPTS is ignored
804 * unless IPV6_RTHDR is set (RFC3542).
807 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst0opt
);
810 ipv6_push_exthdr(skb
, proto
, NEXTHDR_HOP
, opt
->hopopt
);
813 void ipv6_push_frag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
, u8
*proto
)
816 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst1opt
);
819 struct ipv6_txoptions
*
820 ipv6_dup_options(struct sock
*sk
, struct ipv6_txoptions
*opt
)
822 struct ipv6_txoptions
*opt2
;
824 opt2
= sock_kmalloc(sk
, opt
->tot_len
, GFP_ATOMIC
);
826 long dif
= (char*)opt2
- (char*)opt
;
827 memcpy(opt2
, opt
, opt
->tot_len
);
829 *((char**)&opt2
->hopopt
) += dif
;
831 *((char**)&opt2
->dst0opt
) += dif
;
833 *((char**)&opt2
->dst1opt
) += dif
;
835 *((char**)&opt2
->srcrt
) += dif
;
840 EXPORT_SYMBOL_GPL(ipv6_dup_options
);
842 static int ipv6_renew_option(void *ohdr
,
843 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
,
845 struct ipv6_opt_hdr
**hdr
,
850 memcpy(*p
, ohdr
, ipv6_optlen((struct ipv6_opt_hdr
*)ohdr
));
851 *hdr
= (struct ipv6_opt_hdr
*)*p
;
852 *p
+= CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
));
856 if (copy_from_user(*p
, newopt
, newoptlen
))
858 *hdr
= (struct ipv6_opt_hdr
*)*p
;
859 if (ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
) > newoptlen
)
861 *p
+= CMSG_ALIGN(newoptlen
);
867 struct ipv6_txoptions
*
868 ipv6_renew_options(struct sock
*sk
, struct ipv6_txoptions
*opt
,
870 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
)
874 struct ipv6_txoptions
*opt2
;
878 if (newtype
!= IPV6_HOPOPTS
&& opt
->hopopt
)
879 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->hopopt
));
880 if (newtype
!= IPV6_RTHDRDSTOPTS
&& opt
->dst0opt
)
881 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst0opt
));
882 if (newtype
!= IPV6_RTHDR
&& opt
->srcrt
)
883 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->srcrt
));
884 if (newtype
!= IPV6_DSTOPTS
&& opt
->dst1opt
)
885 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst1opt
));
888 if (newopt
&& newoptlen
)
889 tot_len
+= CMSG_ALIGN(newoptlen
);
894 tot_len
+= sizeof(*opt2
);
895 opt2
= sock_kmalloc(sk
, tot_len
, GFP_ATOMIC
);
897 return ERR_PTR(-ENOBUFS
);
899 memset(opt2
, 0, tot_len
);
901 opt2
->tot_len
= tot_len
;
902 p
= (char *)(opt2
+ 1);
904 err
= ipv6_renew_option(opt
? opt
->hopopt
: NULL
, newopt
, newoptlen
,
905 newtype
!= IPV6_HOPOPTS
,
910 err
= ipv6_renew_option(opt
? opt
->dst0opt
: NULL
, newopt
, newoptlen
,
911 newtype
!= IPV6_RTHDRDSTOPTS
,
916 err
= ipv6_renew_option(opt
? opt
->srcrt
: NULL
, newopt
, newoptlen
,
917 newtype
!= IPV6_RTHDR
,
918 (struct ipv6_opt_hdr
**)&opt2
->srcrt
, &p
);
922 err
= ipv6_renew_option(opt
? opt
->dst1opt
: NULL
, newopt
, newoptlen
,
923 newtype
!= IPV6_DSTOPTS
,
928 opt2
->opt_nflen
= (opt2
->hopopt
? ipv6_optlen(opt2
->hopopt
) : 0) +
929 (opt2
->dst0opt
? ipv6_optlen(opt2
->dst0opt
) : 0) +
930 (opt2
->srcrt
? ipv6_optlen(opt2
->srcrt
) : 0);
931 opt2
->opt_flen
= (opt2
->dst1opt
? ipv6_optlen(opt2
->dst1opt
) : 0);
935 sock_kfree_s(sk
, opt2
, opt2
->tot_len
);
939 struct ipv6_txoptions
*ipv6_fixup_options(struct ipv6_txoptions
*opt_space
,
940 struct ipv6_txoptions
*opt
)
943 * ignore the dest before srcrt unless srcrt is being included.
946 if (opt
&& opt
->dst0opt
&& !opt
->srcrt
) {
947 if (opt_space
!= opt
) {
948 memcpy(opt_space
, opt
, sizeof(*opt_space
));
951 opt
->opt_nflen
-= ipv6_optlen(opt
->dst0opt
);