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
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(IPSTATS_MIB_INHDRERRORS
);
295 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
296 opt
->dst1
= skb
->h
.raw
- skb
->nh
.raw
;
297 #ifdef CONFIG_IPV6_MIP6
301 if (ip6_parse_tlv(tlvprocdestopt_lst
, skbp
)) {
303 skb
->h
.raw
+= ((skb
->h
.raw
[1]+1)<<3);
305 #ifdef CONFIG_IPV6_MIP6
308 opt
->nhoff
= opt
->dst1
;
313 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
317 static struct inet6_protocol destopt_protocol
= {
318 .handler
= ipv6_destopt_rcv
,
319 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
322 void __init
ipv6_destopt_init(void)
324 if (inet6_add_protocol(&destopt_protocol
, IPPROTO_DSTOPTS
) < 0)
325 printk(KERN_ERR
"ipv6_destopt_init: Could not register protocol\n");
328 /********************************
329 NONE header. No data in packet.
330 ********************************/
332 static int ipv6_nodata_rcv(struct sk_buff
**skbp
)
334 struct sk_buff
*skb
= *skbp
;
340 static struct inet6_protocol nodata_protocol
= {
341 .handler
= ipv6_nodata_rcv
,
342 .flags
= INET6_PROTO_NOPOLICY
,
345 void __init
ipv6_nodata_init(void)
347 if (inet6_add_protocol(&nodata_protocol
, IPPROTO_NONE
) < 0)
348 printk(KERN_ERR
"ipv6_nodata_init: Could not register protocol\n");
351 /********************************
353 ********************************/
355 static int ipv6_rthdr_rcv(struct sk_buff
**skbp
)
357 struct sk_buff
*skb
= *skbp
;
358 struct inet6_skb_parm
*opt
= IP6CB(skb
);
359 struct in6_addr
*addr
= NULL
;
360 struct in6_addr daddr
;
363 struct ipv6_rt_hdr
*hdr
;
364 struct rt0_hdr
*rthdr
;
366 if (!pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+8) ||
367 !pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+((skb
->h
.raw
[1]+1)<<3))) {
368 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
373 hdr
= (struct ipv6_rt_hdr
*) skb
->h
.raw
;
375 if (ipv6_addr_is_multicast(&skb
->nh
.ipv6h
->daddr
) ||
376 skb
->pkt_type
!= PACKET_HOST
) {
377 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS
);
383 if (hdr
->segments_left
== 0) {
385 #ifdef CONFIG_IPV6_MIP6
386 case IPV6_SRCRT_TYPE_2
:
387 /* Silently discard type 2 header unless it was
391 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS
);
401 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
402 opt
->srcrt
= skb
->h
.raw
- skb
->nh
.raw
;
403 skb
->h
.raw
+= (hdr
->hdrlen
+ 1) << 3;
404 opt
->dst0
= opt
->dst1
;
406 opt
->nhoff
= (&hdr
->nexthdr
) - skb
->nh
.raw
;
411 case IPV6_SRCRT_TYPE_0
:
412 if (hdr
->hdrlen
& 0x01) {
413 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
414 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->hdrlen
) - skb
->nh
.raw
);
418 #ifdef CONFIG_IPV6_MIP6
419 case IPV6_SRCRT_TYPE_2
:
420 /* Silently discard invalid RTH type 2 */
421 if (hdr
->hdrlen
!= 2 || hdr
->segments_left
!= 1) {
422 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
429 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
430 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->type
) - skb
->nh
.raw
);
435 * This is the routing header forwarding algorithm from
439 n
= hdr
->hdrlen
>> 1;
441 if (hdr
->segments_left
> n
) {
442 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
443 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->segments_left
) - skb
->nh
.raw
);
447 /* We are about to mangle packet header. Be careful!
448 Do not damage packets queued somewhere.
450 if (skb_cloned(skb
)) {
451 struct sk_buff
*skb2
= skb_copy(skb
, GFP_ATOMIC
);
453 /* the copy is a forwarded packet */
455 IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS
);
460 hdr
= (struct ipv6_rt_hdr
*) skb2
->h
.raw
;
463 if (skb
->ip_summed
== CHECKSUM_COMPLETE
)
464 skb
->ip_summed
= CHECKSUM_NONE
;
466 i
= n
- --hdr
->segments_left
;
468 rthdr
= (struct rt0_hdr
*) hdr
;
473 #ifdef CONFIG_IPV6_MIP6
474 case IPV6_SRCRT_TYPE_2
:
475 if (xfrm6_input_addr(skb
, (xfrm_address_t
*)addr
,
476 (xfrm_address_t
*)&skb
->nh
.ipv6h
->saddr
,
477 IPPROTO_ROUTING
) < 0) {
478 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS
);
482 if (!ipv6_chk_home_addr(addr
)) {
483 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS
);
493 if (ipv6_addr_is_multicast(addr
)) {
494 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS
);
499 ipv6_addr_copy(&daddr
, addr
);
500 ipv6_addr_copy(addr
, &skb
->nh
.ipv6h
->daddr
);
501 ipv6_addr_copy(&skb
->nh
.ipv6h
->daddr
, &daddr
);
503 dst_release(xchg(&skb
->dst
, NULL
));
504 ip6_route_input(skb
);
505 if (skb
->dst
->error
) {
506 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
511 if (skb
->dst
->dev
->flags
&IFF_LOOPBACK
) {
512 if (skb
->nh
.ipv6h
->hop_limit
<= 1) {
513 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
514 icmpv6_send(skb
, ICMPV6_TIME_EXCEED
, ICMPV6_EXC_HOPLIMIT
,
519 skb
->nh
.ipv6h
->hop_limit
--;
523 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
528 static struct inet6_protocol rthdr_protocol
= {
529 .handler
= ipv6_rthdr_rcv
,
530 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
533 void __init
ipv6_rthdr_init(void)
535 if (inet6_add_protocol(&rthdr_protocol
, IPPROTO_ROUTING
) < 0)
536 printk(KERN_ERR
"ipv6_rthdr_init: Could not register protocol\n");
540 This function inverts received rthdr.
541 NOTE: specs allow to make it automatically only if
542 packet authenticated.
544 I will not discuss it here (though, I am really pissed off at
545 this stupid requirement making rthdr idea useless)
547 Actually, it creates severe problems for us.
548 Embryonic requests has no associated sockets,
549 so that user have no control over it and
550 cannot not only to set reply options, but
551 even to know, that someone wants to connect
554 For now we need to test the engine, so that I created
555 temporary (or permanent) backdoor.
556 If listening socket set IPV6_RTHDR to 2, then we invert header.
560 struct ipv6_txoptions
*
561 ipv6_invert_rthdr(struct sock
*sk
, struct ipv6_rt_hdr
*hdr
)
565 [ H1 -> H2 -> ... H_prev ] daddr=ME
568 [ H_prev -> ... -> H1 ] daddr =sender
570 Note, that IP output engine will rewrite this rthdr
571 by rotating it left by one addr.
575 struct rt0_hdr
*rthdr
= (struct rt0_hdr
*)hdr
;
576 struct rt0_hdr
*irthdr
;
577 struct ipv6_txoptions
*opt
;
578 int hdrlen
= ipv6_optlen(hdr
);
580 if (hdr
->segments_left
||
581 hdr
->type
!= IPV6_SRCRT_TYPE_0
||
585 n
= hdr
->hdrlen
>> 1;
586 opt
= sock_kmalloc(sk
, sizeof(*opt
) + hdrlen
, GFP_ATOMIC
);
589 memset(opt
, 0, sizeof(*opt
));
590 opt
->tot_len
= sizeof(*opt
) + hdrlen
;
591 opt
->srcrt
= (void*)(opt
+1);
592 opt
->opt_nflen
= hdrlen
;
594 memcpy(opt
->srcrt
, hdr
, sizeof(*hdr
));
595 irthdr
= (struct rt0_hdr
*)opt
->srcrt
;
596 irthdr
->reserved
= 0;
597 opt
->srcrt
->segments_left
= n
;
599 memcpy(irthdr
->addr
+i
, rthdr
->addr
+(n
-1-i
), 16);
603 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr
);
605 /**********************************
607 **********************************/
609 /* Router Alert as of RFC 2711 */
611 static int ipv6_hop_ra(struct sk_buff
**skbp
, int optoff
)
613 struct sk_buff
*skb
= *skbp
;
615 if (skb
->nh
.raw
[optoff
+1] == 2) {
616 IP6CB(skb
)->ra
= optoff
;
619 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_ra: wrong RA length %d\n",
620 skb
->nh
.raw
[optoff
+1]);
627 static int ipv6_hop_jumbo(struct sk_buff
**skbp
, int optoff
)
629 struct sk_buff
*skb
= *skbp
;
632 if (skb
->nh
.raw
[optoff
+1] != 4 || (optoff
&3) != 2) {
633 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
634 skb
->nh
.raw
[optoff
+1]);
635 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
639 pkt_len
= ntohl(*(u32
*)(skb
->nh
.raw
+optoff
+2));
640 if (pkt_len
<= IPV6_MAXPLEN
) {
641 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
642 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
+2);
645 if (skb
->nh
.ipv6h
->payload_len
) {
646 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS
);
647 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
);
651 if (pkt_len
> skb
->len
- sizeof(struct ipv6hdr
)) {
652 IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS
);
656 if (pskb_trim_rcsum(skb
, pkt_len
+ sizeof(struct ipv6hdr
)))
666 static struct tlvtype_proc tlvprochopopt_lst
[] = {
668 .type
= IPV6_TLV_ROUTERALERT
,
672 .type
= IPV6_TLV_JUMBO
,
673 .func
= ipv6_hop_jumbo
,
678 int ipv6_parse_hopopts(struct sk_buff
**skbp
)
680 struct sk_buff
*skb
= *skbp
;
681 struct inet6_skb_parm
*opt
= IP6CB(skb
);
684 * skb->nh.raw is equal to skb->data, and
685 * skb->h.raw - skb->nh.raw is always equal to
686 * sizeof(struct ipv6hdr) by definition of
687 * hop-by-hop options.
689 if (!pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + 8) ||
690 !pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + ((skb
->h
.raw
[1] + 1) << 3))) {
695 opt
->hop
= sizeof(struct ipv6hdr
);
696 if (ip6_parse_tlv(tlvprochopopt_lst
, skbp
)) {
698 skb
->h
.raw
+= (skb
->h
.raw
[1]+1)<<3;
700 opt
->nhoff
= sizeof(struct ipv6hdr
);
707 * Creating outbound headers.
709 * "build" functions work when skb is filled from head to tail (datagram)
710 * "push" functions work when headers are added from tail to head (tcp)
712 * In both cases we assume, that caller reserved enough room
716 static void ipv6_push_rthdr(struct sk_buff
*skb
, u8
*proto
,
717 struct ipv6_rt_hdr
*opt
,
718 struct in6_addr
**addr_p
)
720 struct rt0_hdr
*phdr
, *ihdr
;
723 ihdr
= (struct rt0_hdr
*) opt
;
725 phdr
= (struct rt0_hdr
*) skb_push(skb
, (ihdr
->rt_hdr
.hdrlen
+ 1) << 3);
726 memcpy(phdr
, ihdr
, sizeof(struct rt0_hdr
));
728 hops
= ihdr
->rt_hdr
.hdrlen
>> 1;
731 memcpy(phdr
->addr
, ihdr
->addr
+ 1,
732 (hops
- 1) * sizeof(struct in6_addr
));
734 ipv6_addr_copy(phdr
->addr
+ (hops
- 1), *addr_p
);
735 *addr_p
= ihdr
->addr
;
737 phdr
->rt_hdr
.nexthdr
= *proto
;
738 *proto
= NEXTHDR_ROUTING
;
741 static void ipv6_push_exthdr(struct sk_buff
*skb
, u8
*proto
, u8 type
, struct ipv6_opt_hdr
*opt
)
743 struct ipv6_opt_hdr
*h
= (struct ipv6_opt_hdr
*)skb_push(skb
, ipv6_optlen(opt
));
745 memcpy(h
, opt
, ipv6_optlen(opt
));
750 void ipv6_push_nfrag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
,
752 struct in6_addr
**daddr
)
755 ipv6_push_rthdr(skb
, proto
, opt
->srcrt
, daddr
);
757 * IPV6_RTHDRDSTOPTS is ignored
758 * unless IPV6_RTHDR is set (RFC3542).
761 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst0opt
);
764 ipv6_push_exthdr(skb
, proto
, NEXTHDR_HOP
, opt
->hopopt
);
767 void ipv6_push_frag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
, u8
*proto
)
770 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst1opt
);
773 struct ipv6_txoptions
*
774 ipv6_dup_options(struct sock
*sk
, struct ipv6_txoptions
*opt
)
776 struct ipv6_txoptions
*opt2
;
778 opt2
= sock_kmalloc(sk
, opt
->tot_len
, GFP_ATOMIC
);
780 long dif
= (char*)opt2
- (char*)opt
;
781 memcpy(opt2
, opt
, opt
->tot_len
);
783 *((char**)&opt2
->hopopt
) += dif
;
785 *((char**)&opt2
->dst0opt
) += dif
;
787 *((char**)&opt2
->dst1opt
) += dif
;
789 *((char**)&opt2
->srcrt
) += dif
;
794 EXPORT_SYMBOL_GPL(ipv6_dup_options
);
796 static int ipv6_renew_option(void *ohdr
,
797 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
,
799 struct ipv6_opt_hdr
**hdr
,
804 memcpy(*p
, ohdr
, ipv6_optlen((struct ipv6_opt_hdr
*)ohdr
));
805 *hdr
= (struct ipv6_opt_hdr
*)*p
;
806 *p
+= CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
));
810 if (copy_from_user(*p
, newopt
, newoptlen
))
812 *hdr
= (struct ipv6_opt_hdr
*)*p
;
813 if (ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
) > newoptlen
)
815 *p
+= CMSG_ALIGN(newoptlen
);
821 struct ipv6_txoptions
*
822 ipv6_renew_options(struct sock
*sk
, struct ipv6_txoptions
*opt
,
824 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
)
828 struct ipv6_txoptions
*opt2
;
832 if (newtype
!= IPV6_HOPOPTS
&& opt
->hopopt
)
833 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->hopopt
));
834 if (newtype
!= IPV6_RTHDRDSTOPTS
&& opt
->dst0opt
)
835 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst0opt
));
836 if (newtype
!= IPV6_RTHDR
&& opt
->srcrt
)
837 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->srcrt
));
838 if (newtype
!= IPV6_DSTOPTS
&& opt
->dst1opt
)
839 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst1opt
));
842 if (newopt
&& newoptlen
)
843 tot_len
+= CMSG_ALIGN(newoptlen
);
848 tot_len
+= sizeof(*opt2
);
849 opt2
= sock_kmalloc(sk
, tot_len
, GFP_ATOMIC
);
851 return ERR_PTR(-ENOBUFS
);
853 memset(opt2
, 0, tot_len
);
855 opt2
->tot_len
= tot_len
;
856 p
= (char *)(opt2
+ 1);
858 err
= ipv6_renew_option(opt
? opt
->hopopt
: NULL
, newopt
, newoptlen
,
859 newtype
!= IPV6_HOPOPTS
,
864 err
= ipv6_renew_option(opt
? opt
->dst0opt
: NULL
, newopt
, newoptlen
,
865 newtype
!= IPV6_RTHDRDSTOPTS
,
870 err
= ipv6_renew_option(opt
? opt
->srcrt
: NULL
, newopt
, newoptlen
,
871 newtype
!= IPV6_RTHDR
,
872 (struct ipv6_opt_hdr
**)&opt2
->srcrt
, &p
);
876 err
= ipv6_renew_option(opt
? opt
->dst1opt
: NULL
, newopt
, newoptlen
,
877 newtype
!= IPV6_DSTOPTS
,
882 opt2
->opt_nflen
= (opt2
->hopopt
? ipv6_optlen(opt2
->hopopt
) : 0) +
883 (opt2
->dst0opt
? ipv6_optlen(opt2
->dst0opt
) : 0) +
884 (opt2
->srcrt
? ipv6_optlen(opt2
->srcrt
) : 0);
885 opt2
->opt_flen
= (opt2
->dst1opt
? ipv6_optlen(opt2
->dst1opt
) : 0);
889 sock_kfree_s(sk
, opt2
, opt2
->tot_len
);
893 struct ipv6_txoptions
*ipv6_fixup_options(struct ipv6_txoptions
*opt_space
,
894 struct ipv6_txoptions
*opt
)
897 * ignore the dest before srcrt unless srcrt is being included.
900 if (opt
&& opt
->dst0opt
&& !opt
->srcrt
) {
901 if (opt_space
!= opt
) {
902 memcpy(opt_space
, opt
, sizeof(*opt_space
));
905 opt
->opt_nflen
-= ipv6_optlen(opt
->dst0opt
);