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/sched.h>
31 #include <linux/net.h>
32 #include <linux/netdevice.h>
33 #include <linux/in6.h>
34 #include <linux/icmpv6.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
50 #include <asm/uaccess.h>
52 int ipv6_find_tlv(struct sk_buff
*skb
, int offset
, int type
)
54 int packet_len
= skb
->tail
- skb
->nh
.raw
;
55 struct ipv6_opt_hdr
*hdr
;
58 if (offset
+ 2 > packet_len
)
60 hdr
= (struct ipv6_opt_hdr
*)(skb
->nh
.raw
+ offset
);
61 len
= ((hdr
->hdrlen
+ 1) << 3);
63 if (offset
+ len
> packet_len
)
70 int opttype
= skb
->nh
.raw
[offset
];
81 optlen
= skb
->nh
.raw
[offset
+ 1] + 2;
95 * Parsing tlv encoded headers.
97 * Parsing function "func" returns 1, if parsing succeed
98 * and 0, if it failed.
99 * It MUST NOT touch skb->h.
102 struct tlvtype_proc
{
104 int (*func
)(struct sk_buff
**skbp
, int offset
);
107 /*********************
109 *********************/
111 /* An unknown option is detected, decide what to do */
113 static int ip6_tlvopt_unknown(struct sk_buff
**skbp
, int optoff
)
115 struct sk_buff
*skb
= *skbp
;
117 switch ((skb
->nh
.raw
[optoff
] & 0xC0) >> 6) {
121 case 1: /* drop packet */
124 case 3: /* Send ICMP if not a multicast address and drop packet */
125 /* Actually, it is redundant check. icmp_send
126 will recheck in any case.
128 if (ipv6_addr_is_multicast(&skb
->nh
.ipv6h
->daddr
))
130 case 2: /* send ICMP PARM PROB regardless and drop packet */
131 icmpv6_param_prob(skb
, ICMPV6_UNK_OPTION
, optoff
);
139 /* Parse tlv encoded option header (hop-by-hop or destination) */
141 static int ip6_parse_tlv(struct tlvtype_proc
*procs
, struct sk_buff
**skbp
)
143 struct sk_buff
*skb
= *skbp
;
144 struct tlvtype_proc
*curr
;
145 int off
= skb
->h
.raw
- skb
->nh
.raw
;
146 int len
= ((skb
->h
.raw
[1]+1)<<3);
148 if ((skb
->h
.raw
+ len
) - skb
->data
> skb_headlen(skb
))
155 int optlen
= skb
->nh
.raw
[off
+1]+2;
157 switch (skb
->nh
.raw
[off
]) {
165 default: /* Other TLV code so scan list */
168 for (curr
=procs
; curr
->type
>= 0; curr
++) {
169 if (curr
->type
== skb
->nh
.raw
[off
]) {
170 /* type specific length/alignment
171 checks will be performed in the
173 if (curr
->func(skbp
, off
) == 0)
178 if (curr
->type
< 0) {
179 if (ip6_tlvopt_unknown(skbp
, off
) == 0)
194 /*****************************
195 Destination options header.
196 *****************************/
198 #ifdef CONFIG_IPV6_MIP6
199 static int ipv6_dest_hao(struct sk_buff
**skbp
, int optoff
)
201 struct sk_buff
*skb
= *skbp
;
202 struct ipv6_destopt_hao
*hao
;
203 struct inet6_skb_parm
*opt
= IP6CB(skb
);
204 struct ipv6hdr
*ipv6h
= (struct ipv6hdr
*)skb
->nh
.raw
;
205 struct in6_addr tmp_addr
;
209 LIMIT_NETDEBUG(KERN_DEBUG
"hao duplicated\n");
212 opt
->dsthao
= opt
->dst1
;
215 hao
= (struct ipv6_destopt_hao
*)(skb
->nh
.raw
+ optoff
);
217 if (hao
->length
!= 16) {
219 KERN_DEBUG
"hao invalid option length = %d\n", hao
->length
);
223 if (!(ipv6_addr_type(&hao
->addr
) & IPV6_ADDR_UNICAST
)) {
225 KERN_DEBUG
"hao is not an unicast addr: " NIP6_FMT
"\n", NIP6(hao
->addr
));
229 ret
= xfrm6_input_addr(skb
, (xfrm_address_t
*)&ipv6h
->daddr
,
230 (xfrm_address_t
*)&hao
->addr
, IPPROTO_DSTOPTS
);
231 if (unlikely(ret
< 0))
234 if (skb_cloned(skb
)) {
235 struct sk_buff
*skb2
= skb_copy(skb
, GFP_ATOMIC
);
236 struct inet6_skb_parm
*opt2
;
242 memcpy(opt2
, opt
, sizeof(*opt2
));
246 /* update all variable using below by copied skbuff */
248 hao
= (struct ipv6_destopt_hao
*)(skb2
->nh
.raw
+ optoff
);
249 ipv6h
= (struct ipv6hdr
*)skb2
->nh
.raw
;
252 if (skb
->ip_summed
== CHECKSUM_COMPLETE
)
253 skb
->ip_summed
= CHECKSUM_NONE
;
255 ipv6_addr_copy(&tmp_addr
, &ipv6h
->saddr
);
256 ipv6_addr_copy(&ipv6h
->saddr
, &hao
->addr
);
257 ipv6_addr_copy(&hao
->addr
, &tmp_addr
);
259 if (skb
->tstamp
.off_sec
== 0)
260 __net_timestamp(skb
);
270 static struct tlvtype_proc tlvprocdestopt_lst
[] = {
271 #ifdef CONFIG_IPV6_MIP6
273 .type
= IPV6_TLV_HAO
,
274 .func
= ipv6_dest_hao
,
280 static int ipv6_destopt_rcv(struct sk_buff
**skbp
)
282 struct sk_buff
*skb
= *skbp
;
283 struct inet6_skb_parm
*opt
= IP6CB(skb
);
284 #ifdef CONFIG_IPV6_MIP6
287 struct dst_entry
*dst
;
289 if (!pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+8) ||
290 !pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+((skb
->h
.raw
[1]+1)<<3))) {
291 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
292 IPSTATS_MIB_INHDRERRORS
);
297 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
298 opt
->dst1
= skb
->h
.raw
- skb
->nh
.raw
;
299 #ifdef CONFIG_IPV6_MIP6
303 dst
= dst_clone(skb
->dst
);
304 if (ip6_parse_tlv(tlvprocdestopt_lst
, skbp
)) {
307 skb
->h
.raw
+= ((skb
->h
.raw
[1]+1)<<3);
309 #ifdef CONFIG_IPV6_MIP6
312 opt
->nhoff
= opt
->dst1
;
317 IP6_INC_STATS_BH(ip6_dst_idev(dst
), IPSTATS_MIB_INHDRERRORS
);
322 static struct inet6_protocol destopt_protocol
= {
323 .handler
= ipv6_destopt_rcv
,
324 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
327 void __init
ipv6_destopt_init(void)
329 if (inet6_add_protocol(&destopt_protocol
, IPPROTO_DSTOPTS
) < 0)
330 printk(KERN_ERR
"ipv6_destopt_init: Could not register protocol\n");
333 /********************************
334 NONE header. No data in packet.
335 ********************************/
337 static int ipv6_nodata_rcv(struct sk_buff
**skbp
)
339 struct sk_buff
*skb
= *skbp
;
345 static struct inet6_protocol nodata_protocol
= {
346 .handler
= ipv6_nodata_rcv
,
347 .flags
= INET6_PROTO_NOPOLICY
,
350 void __init
ipv6_nodata_init(void)
352 if (inet6_add_protocol(&nodata_protocol
, IPPROTO_NONE
) < 0)
353 printk(KERN_ERR
"ipv6_nodata_init: Could not register protocol\n");
356 /********************************
358 ********************************/
360 static int ipv6_rthdr_rcv(struct sk_buff
**skbp
)
362 struct sk_buff
*skb
= *skbp
;
363 struct inet6_skb_parm
*opt
= IP6CB(skb
);
364 struct in6_addr
*addr
= NULL
;
365 struct in6_addr daddr
;
368 struct ipv6_rt_hdr
*hdr
;
369 struct rt0_hdr
*rthdr
;
371 if (!pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+8) ||
372 !pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+((skb
->h
.raw
[1]+1)<<3))) {
373 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
374 IPSTATS_MIB_INHDRERRORS
);
379 hdr
= (struct ipv6_rt_hdr
*) skb
->h
.raw
;
381 if (ipv6_addr_is_multicast(&skb
->nh
.ipv6h
->daddr
) ||
382 skb
->pkt_type
!= PACKET_HOST
) {
383 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
384 IPSTATS_MIB_INADDRERRORS
);
390 if (hdr
->segments_left
== 0) {
392 #ifdef CONFIG_IPV6_MIP6
393 case IPV6_SRCRT_TYPE_2
:
394 /* Silently discard type 2 header unless it was
398 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
399 IPSTATS_MIB_INADDRERRORS
);
409 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
410 opt
->srcrt
= skb
->h
.raw
- skb
->nh
.raw
;
411 skb
->h
.raw
+= (hdr
->hdrlen
+ 1) << 3;
412 opt
->dst0
= opt
->dst1
;
414 opt
->nhoff
= (&hdr
->nexthdr
) - skb
->nh
.raw
;
419 case IPV6_SRCRT_TYPE_0
:
420 if (hdr
->hdrlen
& 0x01) {
421 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
422 IPSTATS_MIB_INHDRERRORS
);
423 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->hdrlen
) - skb
->nh
.raw
);
427 #ifdef CONFIG_IPV6_MIP6
428 case IPV6_SRCRT_TYPE_2
:
429 /* Silently discard invalid RTH type 2 */
430 if (hdr
->hdrlen
!= 2 || hdr
->segments_left
!= 1) {
431 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
432 IPSTATS_MIB_INHDRERRORS
);
439 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
440 IPSTATS_MIB_INHDRERRORS
);
441 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->type
) - skb
->nh
.raw
);
446 * This is the routing header forwarding algorithm from
450 n
= hdr
->hdrlen
>> 1;
452 if (hdr
->segments_left
> n
) {
453 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
454 IPSTATS_MIB_INHDRERRORS
);
455 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->segments_left
) - skb
->nh
.raw
);
459 /* We are about to mangle packet header. Be careful!
460 Do not damage packets queued somewhere.
462 if (skb_cloned(skb
)) {
463 struct sk_buff
*skb2
= skb_copy(skb
, GFP_ATOMIC
);
464 /* the copy is a forwarded packet */
466 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
467 IPSTATS_MIB_OUTDISCARDS
);
474 hdr
= (struct ipv6_rt_hdr
*) skb2
->h
.raw
;
477 if (skb
->ip_summed
== CHECKSUM_COMPLETE
)
478 skb
->ip_summed
= CHECKSUM_NONE
;
480 i
= n
- --hdr
->segments_left
;
482 rthdr
= (struct rt0_hdr
*) hdr
;
487 #ifdef CONFIG_IPV6_MIP6
488 case IPV6_SRCRT_TYPE_2
:
489 if (xfrm6_input_addr(skb
, (xfrm_address_t
*)addr
,
490 (xfrm_address_t
*)&skb
->nh
.ipv6h
->saddr
,
491 IPPROTO_ROUTING
) < 0) {
492 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
493 IPSTATS_MIB_INADDRERRORS
);
497 if (!ipv6_chk_home_addr(addr
)) {
498 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
499 IPSTATS_MIB_INADDRERRORS
);
509 if (ipv6_addr_is_multicast(addr
)) {
510 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
511 IPSTATS_MIB_INADDRERRORS
);
516 ipv6_addr_copy(&daddr
, addr
);
517 ipv6_addr_copy(addr
, &skb
->nh
.ipv6h
->daddr
);
518 ipv6_addr_copy(&skb
->nh
.ipv6h
->daddr
, &daddr
);
520 dst_release(xchg(&skb
->dst
, NULL
));
521 ip6_route_input(skb
);
522 if (skb
->dst
->error
) {
523 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
528 if (skb
->dst
->dev
->flags
&IFF_LOOPBACK
) {
529 if (skb
->nh
.ipv6h
->hop_limit
<= 1) {
530 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
531 IPSTATS_MIB_INHDRERRORS
);
532 icmpv6_send(skb
, ICMPV6_TIME_EXCEED
, ICMPV6_EXC_HOPLIMIT
,
537 skb
->nh
.ipv6h
->hop_limit
--;
541 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
546 static struct inet6_protocol rthdr_protocol
= {
547 .handler
= ipv6_rthdr_rcv
,
548 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
551 void __init
ipv6_rthdr_init(void)
553 if (inet6_add_protocol(&rthdr_protocol
, IPPROTO_ROUTING
) < 0)
554 printk(KERN_ERR
"ipv6_rthdr_init: Could not register protocol\n");
558 This function inverts received rthdr.
559 NOTE: specs allow to make it automatically only if
560 packet authenticated.
562 I will not discuss it here (though, I am really pissed off at
563 this stupid requirement making rthdr idea useless)
565 Actually, it creates severe problems for us.
566 Embryonic requests has no associated sockets,
567 so that user have no control over it and
568 cannot not only to set reply options, but
569 even to know, that someone wants to connect
572 For now we need to test the engine, so that I created
573 temporary (or permanent) backdoor.
574 If listening socket set IPV6_RTHDR to 2, then we invert header.
578 struct ipv6_txoptions
*
579 ipv6_invert_rthdr(struct sock
*sk
, struct ipv6_rt_hdr
*hdr
)
583 [ H1 -> H2 -> ... H_prev ] daddr=ME
586 [ H_prev -> ... -> H1 ] daddr =sender
588 Note, that IP output engine will rewrite this rthdr
589 by rotating it left by one addr.
593 struct rt0_hdr
*rthdr
= (struct rt0_hdr
*)hdr
;
594 struct rt0_hdr
*irthdr
;
595 struct ipv6_txoptions
*opt
;
596 int hdrlen
= ipv6_optlen(hdr
);
598 if (hdr
->segments_left
||
599 hdr
->type
!= IPV6_SRCRT_TYPE_0
||
603 n
= hdr
->hdrlen
>> 1;
604 opt
= sock_kmalloc(sk
, sizeof(*opt
) + hdrlen
, GFP_ATOMIC
);
607 memset(opt
, 0, sizeof(*opt
));
608 opt
->tot_len
= sizeof(*opt
) + hdrlen
;
609 opt
->srcrt
= (void*)(opt
+1);
610 opt
->opt_nflen
= hdrlen
;
612 memcpy(opt
->srcrt
, hdr
, sizeof(*hdr
));
613 irthdr
= (struct rt0_hdr
*)opt
->srcrt
;
614 irthdr
->reserved
= 0;
615 opt
->srcrt
->segments_left
= n
;
617 memcpy(irthdr
->addr
+i
, rthdr
->addr
+(n
-1-i
), 16);
621 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr
);
623 /**********************************
625 **********************************/
627 /* Router Alert as of RFC 2711 */
629 static int ipv6_hop_ra(struct sk_buff
**skbp
, int optoff
)
631 struct sk_buff
*skb
= *skbp
;
633 if (skb
->nh
.raw
[optoff
+1] == 2) {
634 IP6CB(skb
)->ra
= optoff
;
637 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_ra: wrong RA length %d\n",
638 skb
->nh
.raw
[optoff
+1]);
645 static int ipv6_hop_jumbo(struct sk_buff
**skbp
, int optoff
)
647 struct sk_buff
*skb
= *skbp
;
650 if (skb
->nh
.raw
[optoff
+1] != 4 || (optoff
&3) != 2) {
651 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
652 skb
->nh
.raw
[optoff
+1]);
653 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
654 IPSTATS_MIB_INHDRERRORS
);
658 pkt_len
= ntohl(*(__be32
*)(skb
->nh
.raw
+optoff
+2));
659 if (pkt_len
<= IPV6_MAXPLEN
) {
660 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
), IPSTATS_MIB_INHDRERRORS
);
661 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
+2);
664 if (skb
->nh
.ipv6h
->payload_len
) {
665 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
), IPSTATS_MIB_INHDRERRORS
);
666 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
);
670 if (pkt_len
> skb
->len
- sizeof(struct ipv6hdr
)) {
671 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
), IPSTATS_MIB_INTRUNCATEDPKTS
);
675 if (pskb_trim_rcsum(skb
, pkt_len
+ sizeof(struct ipv6hdr
)))
685 static struct tlvtype_proc tlvprochopopt_lst
[] = {
687 .type
= IPV6_TLV_ROUTERALERT
,
691 .type
= IPV6_TLV_JUMBO
,
692 .func
= ipv6_hop_jumbo
,
697 int ipv6_parse_hopopts(struct sk_buff
**skbp
)
699 struct sk_buff
*skb
= *skbp
;
700 struct inet6_skb_parm
*opt
= IP6CB(skb
);
703 * skb->nh.raw is equal to skb->data, and
704 * skb->h.raw - skb->nh.raw is always equal to
705 * sizeof(struct ipv6hdr) by definition of
706 * hop-by-hop options.
708 if (!pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + 8) ||
709 !pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + ((skb
->h
.raw
[1] + 1) << 3))) {
714 opt
->hop
= sizeof(struct ipv6hdr
);
715 if (ip6_parse_tlv(tlvprochopopt_lst
, skbp
)) {
717 skb
->h
.raw
+= (skb
->h
.raw
[1]+1)<<3;
719 opt
->nhoff
= sizeof(struct ipv6hdr
);
726 * Creating outbound headers.
728 * "build" functions work when skb is filled from head to tail (datagram)
729 * "push" functions work when headers are added from tail to head (tcp)
731 * In both cases we assume, that caller reserved enough room
735 static void ipv6_push_rthdr(struct sk_buff
*skb
, u8
*proto
,
736 struct ipv6_rt_hdr
*opt
,
737 struct in6_addr
**addr_p
)
739 struct rt0_hdr
*phdr
, *ihdr
;
742 ihdr
= (struct rt0_hdr
*) opt
;
744 phdr
= (struct rt0_hdr
*) skb_push(skb
, (ihdr
->rt_hdr
.hdrlen
+ 1) << 3);
745 memcpy(phdr
, ihdr
, sizeof(struct rt0_hdr
));
747 hops
= ihdr
->rt_hdr
.hdrlen
>> 1;
750 memcpy(phdr
->addr
, ihdr
->addr
+ 1,
751 (hops
- 1) * sizeof(struct in6_addr
));
753 ipv6_addr_copy(phdr
->addr
+ (hops
- 1), *addr_p
);
754 *addr_p
= ihdr
->addr
;
756 phdr
->rt_hdr
.nexthdr
= *proto
;
757 *proto
= NEXTHDR_ROUTING
;
760 static void ipv6_push_exthdr(struct sk_buff
*skb
, u8
*proto
, u8 type
, struct ipv6_opt_hdr
*opt
)
762 struct ipv6_opt_hdr
*h
= (struct ipv6_opt_hdr
*)skb_push(skb
, ipv6_optlen(opt
));
764 memcpy(h
, opt
, ipv6_optlen(opt
));
769 void ipv6_push_nfrag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
,
771 struct in6_addr
**daddr
)
774 ipv6_push_rthdr(skb
, proto
, opt
->srcrt
, daddr
);
776 * IPV6_RTHDRDSTOPTS is ignored
777 * unless IPV6_RTHDR is set (RFC3542).
780 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst0opt
);
783 ipv6_push_exthdr(skb
, proto
, NEXTHDR_HOP
, opt
->hopopt
);
786 void ipv6_push_frag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
, u8
*proto
)
789 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst1opt
);
792 struct ipv6_txoptions
*
793 ipv6_dup_options(struct sock
*sk
, struct ipv6_txoptions
*opt
)
795 struct ipv6_txoptions
*opt2
;
797 opt2
= sock_kmalloc(sk
, opt
->tot_len
, GFP_ATOMIC
);
799 long dif
= (char*)opt2
- (char*)opt
;
800 memcpy(opt2
, opt
, opt
->tot_len
);
802 *((char**)&opt2
->hopopt
) += dif
;
804 *((char**)&opt2
->dst0opt
) += dif
;
806 *((char**)&opt2
->dst1opt
) += dif
;
808 *((char**)&opt2
->srcrt
) += dif
;
813 EXPORT_SYMBOL_GPL(ipv6_dup_options
);
815 static int ipv6_renew_option(void *ohdr
,
816 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
,
818 struct ipv6_opt_hdr
**hdr
,
823 memcpy(*p
, ohdr
, ipv6_optlen((struct ipv6_opt_hdr
*)ohdr
));
824 *hdr
= (struct ipv6_opt_hdr
*)*p
;
825 *p
+= CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
));
829 if (copy_from_user(*p
, newopt
, newoptlen
))
831 *hdr
= (struct ipv6_opt_hdr
*)*p
;
832 if (ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
) > newoptlen
)
834 *p
+= CMSG_ALIGN(newoptlen
);
840 struct ipv6_txoptions
*
841 ipv6_renew_options(struct sock
*sk
, struct ipv6_txoptions
*opt
,
843 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
)
847 struct ipv6_txoptions
*opt2
;
851 if (newtype
!= IPV6_HOPOPTS
&& opt
->hopopt
)
852 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->hopopt
));
853 if (newtype
!= IPV6_RTHDRDSTOPTS
&& opt
->dst0opt
)
854 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst0opt
));
855 if (newtype
!= IPV6_RTHDR
&& opt
->srcrt
)
856 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->srcrt
));
857 if (newtype
!= IPV6_DSTOPTS
&& opt
->dst1opt
)
858 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst1opt
));
861 if (newopt
&& newoptlen
)
862 tot_len
+= CMSG_ALIGN(newoptlen
);
867 tot_len
+= sizeof(*opt2
);
868 opt2
= sock_kmalloc(sk
, tot_len
, GFP_ATOMIC
);
870 return ERR_PTR(-ENOBUFS
);
872 memset(opt2
, 0, tot_len
);
874 opt2
->tot_len
= tot_len
;
875 p
= (char *)(opt2
+ 1);
877 err
= ipv6_renew_option(opt
? opt
->hopopt
: NULL
, newopt
, newoptlen
,
878 newtype
!= IPV6_HOPOPTS
,
883 err
= ipv6_renew_option(opt
? opt
->dst0opt
: NULL
, newopt
, newoptlen
,
884 newtype
!= IPV6_RTHDRDSTOPTS
,
889 err
= ipv6_renew_option(opt
? opt
->srcrt
: NULL
, newopt
, newoptlen
,
890 newtype
!= IPV6_RTHDR
,
891 (struct ipv6_opt_hdr
**)&opt2
->srcrt
, &p
);
895 err
= ipv6_renew_option(opt
? opt
->dst1opt
: NULL
, newopt
, newoptlen
,
896 newtype
!= IPV6_DSTOPTS
,
901 opt2
->opt_nflen
= (opt2
->hopopt
? ipv6_optlen(opt2
->hopopt
) : 0) +
902 (opt2
->dst0opt
? ipv6_optlen(opt2
->dst0opt
) : 0) +
903 (opt2
->srcrt
? ipv6_optlen(opt2
->srcrt
) : 0);
904 opt2
->opt_flen
= (opt2
->dst1opt
? ipv6_optlen(opt2
->dst1opt
) : 0);
908 sock_kfree_s(sk
, opt2
, opt2
->tot_len
);
912 struct ipv6_txoptions
*ipv6_fixup_options(struct ipv6_txoptions
*opt_space
,
913 struct ipv6_txoptions
*opt
)
916 * ignore the dest before srcrt unless srcrt is being included.
919 if (opt
&& opt
->dst0opt
&& !opt
->srcrt
) {
920 if (opt_space
!= opt
) {
921 memcpy(opt_space
, opt
, sizeof(*opt_space
));
924 opt
->opt_nflen
-= ipv6_optlen(opt
->dst0opt
);