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
;
366 struct inet6_dev
*idev
;
368 struct ipv6_rt_hdr
*hdr
;
369 struct rt0_hdr
*rthdr
;
370 int accept_source_route
= ipv6_devconf
.accept_source_route
;
372 if (accept_source_route
< 0 ||
373 ((idev
= in6_dev_get(skb
->dev
)) == NULL
)) {
377 if (idev
->cnf
.accept_source_route
< 0) {
383 if (accept_source_route
> idev
->cnf
.accept_source_route
)
384 accept_source_route
= idev
->cnf
.accept_source_route
;
388 if (!pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+8) ||
389 !pskb_may_pull(skb
, (skb
->h
.raw
-skb
->data
)+((skb
->h
.raw
[1]+1)<<3))) {
390 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
391 IPSTATS_MIB_INHDRERRORS
);
396 hdr
= (struct ipv6_rt_hdr
*) skb
->h
.raw
;
399 #ifdef CONFIG_IPV6_MIP6
400 case IPV6_SRCRT_TYPE_2
:
403 case IPV6_SRCRT_TYPE_0
:
404 if (accept_source_route
> 0)
409 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
410 IPSTATS_MIB_INHDRERRORS
);
411 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->type
) - skb
->nh
.raw
);
415 if (ipv6_addr_is_multicast(&skb
->nh
.ipv6h
->daddr
) ||
416 skb
->pkt_type
!= PACKET_HOST
) {
417 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
418 IPSTATS_MIB_INADDRERRORS
);
424 if (hdr
->segments_left
== 0) {
426 #ifdef CONFIG_IPV6_MIP6
427 case IPV6_SRCRT_TYPE_2
:
428 /* Silently discard type 2 header unless it was
432 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
433 IPSTATS_MIB_INADDRERRORS
);
443 opt
->lastopt
= skb
->h
.raw
- skb
->nh
.raw
;
444 opt
->srcrt
= skb
->h
.raw
- skb
->nh
.raw
;
445 skb
->h
.raw
+= (hdr
->hdrlen
+ 1) << 3;
446 opt
->dst0
= opt
->dst1
;
448 opt
->nhoff
= (&hdr
->nexthdr
) - skb
->nh
.raw
;
453 case IPV6_SRCRT_TYPE_0
:
454 if (hdr
->hdrlen
& 0x01) {
455 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
456 IPSTATS_MIB_INHDRERRORS
);
457 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->hdrlen
) - skb
->nh
.raw
);
461 #ifdef CONFIG_IPV6_MIP6
462 case IPV6_SRCRT_TYPE_2
:
463 /* Silently discard invalid RTH type 2 */
464 if (hdr
->hdrlen
!= 2 || hdr
->segments_left
!= 1) {
465 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
466 IPSTATS_MIB_INHDRERRORS
);
475 * This is the routing header forwarding algorithm from
479 n
= hdr
->hdrlen
>> 1;
481 if (hdr
->segments_left
> n
) {
482 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
483 IPSTATS_MIB_INHDRERRORS
);
484 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, (&hdr
->segments_left
) - skb
->nh
.raw
);
488 /* We are about to mangle packet header. Be careful!
489 Do not damage packets queued somewhere.
491 if (skb_cloned(skb
)) {
492 struct sk_buff
*skb2
= skb_copy(skb
, GFP_ATOMIC
);
493 /* the copy is a forwarded packet */
495 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
496 IPSTATS_MIB_OUTDISCARDS
);
503 hdr
= (struct ipv6_rt_hdr
*) skb2
->h
.raw
;
506 if (skb
->ip_summed
== CHECKSUM_COMPLETE
)
507 skb
->ip_summed
= CHECKSUM_NONE
;
509 i
= n
- --hdr
->segments_left
;
511 rthdr
= (struct rt0_hdr
*) hdr
;
516 #ifdef CONFIG_IPV6_MIP6
517 case IPV6_SRCRT_TYPE_2
:
518 if (xfrm6_input_addr(skb
, (xfrm_address_t
*)addr
,
519 (xfrm_address_t
*)&skb
->nh
.ipv6h
->saddr
,
520 IPPROTO_ROUTING
) < 0) {
521 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
522 IPSTATS_MIB_INADDRERRORS
);
526 if (!ipv6_chk_home_addr(addr
)) {
527 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
528 IPSTATS_MIB_INADDRERRORS
);
538 if (ipv6_addr_is_multicast(addr
)) {
539 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
540 IPSTATS_MIB_INADDRERRORS
);
545 ipv6_addr_copy(&daddr
, addr
);
546 ipv6_addr_copy(addr
, &skb
->nh
.ipv6h
->daddr
);
547 ipv6_addr_copy(&skb
->nh
.ipv6h
->daddr
, &daddr
);
549 dst_release(xchg(&skb
->dst
, NULL
));
550 ip6_route_input(skb
);
551 if (skb
->dst
->error
) {
552 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
557 if (skb
->dst
->dev
->flags
&IFF_LOOPBACK
) {
558 if (skb
->nh
.ipv6h
->hop_limit
<= 1) {
559 IP6_INC_STATS_BH(ip6_dst_idev(skb
->dst
),
560 IPSTATS_MIB_INHDRERRORS
);
561 icmpv6_send(skb
, ICMPV6_TIME_EXCEED
, ICMPV6_EXC_HOPLIMIT
,
566 skb
->nh
.ipv6h
->hop_limit
--;
570 skb_push(skb
, skb
->data
- skb
->nh
.raw
);
575 static struct inet6_protocol rthdr_protocol
= {
576 .handler
= ipv6_rthdr_rcv
,
577 .flags
= INET6_PROTO_NOPOLICY
| INET6_PROTO_GSO_EXTHDR
,
580 void __init
ipv6_rthdr_init(void)
582 if (inet6_add_protocol(&rthdr_protocol
, IPPROTO_ROUTING
) < 0)
583 printk(KERN_ERR
"ipv6_rthdr_init: Could not register protocol\n");
587 This function inverts received rthdr.
588 NOTE: specs allow to make it automatically only if
589 packet authenticated.
591 I will not discuss it here (though, I am really pissed off at
592 this stupid requirement making rthdr idea useless)
594 Actually, it creates severe problems for us.
595 Embryonic requests has no associated sockets,
596 so that user have no control over it and
597 cannot not only to set reply options, but
598 even to know, that someone wants to connect
601 For now we need to test the engine, so that I created
602 temporary (or permanent) backdoor.
603 If listening socket set IPV6_RTHDR to 2, then we invert header.
607 struct ipv6_txoptions
*
608 ipv6_invert_rthdr(struct sock
*sk
, struct ipv6_rt_hdr
*hdr
)
612 [ H1 -> H2 -> ... H_prev ] daddr=ME
615 [ H_prev -> ... -> H1 ] daddr =sender
617 Note, that IP output engine will rewrite this rthdr
618 by rotating it left by one addr.
622 struct rt0_hdr
*rthdr
= (struct rt0_hdr
*)hdr
;
623 struct rt0_hdr
*irthdr
;
624 struct ipv6_txoptions
*opt
;
625 int hdrlen
= ipv6_optlen(hdr
);
627 if (hdr
->segments_left
||
628 hdr
->type
!= IPV6_SRCRT_TYPE_0
||
632 n
= hdr
->hdrlen
>> 1;
633 opt
= sock_kmalloc(sk
, sizeof(*opt
) + hdrlen
, GFP_ATOMIC
);
636 memset(opt
, 0, sizeof(*opt
));
637 opt
->tot_len
= sizeof(*opt
) + hdrlen
;
638 opt
->srcrt
= (void*)(opt
+1);
639 opt
->opt_nflen
= hdrlen
;
641 memcpy(opt
->srcrt
, hdr
, sizeof(*hdr
));
642 irthdr
= (struct rt0_hdr
*)opt
->srcrt
;
643 irthdr
->reserved
= 0;
644 opt
->srcrt
->segments_left
= n
;
646 memcpy(irthdr
->addr
+i
, rthdr
->addr
+(n
-1-i
), 16);
650 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr
);
652 /**********************************
654 **********************************/
657 * Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
659 static inline struct inet6_dev
*ipv6_skb_idev(struct sk_buff
*skb
)
661 return skb
->dst
? ip6_dst_idev(skb
->dst
) : __in6_dev_get(skb
->dev
);
664 /* Router Alert as of RFC 2711 */
666 static int ipv6_hop_ra(struct sk_buff
**skbp
, int optoff
)
668 struct sk_buff
*skb
= *skbp
;
670 if (skb
->nh
.raw
[optoff
+1] == 2) {
671 IP6CB(skb
)->ra
= optoff
;
674 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_ra: wrong RA length %d\n",
675 skb
->nh
.raw
[optoff
+1]);
682 static int ipv6_hop_jumbo(struct sk_buff
**skbp
, int optoff
)
684 struct sk_buff
*skb
= *skbp
;
687 if (skb
->nh
.raw
[optoff
+1] != 4 || (optoff
&3) != 2) {
688 LIMIT_NETDEBUG(KERN_DEBUG
"ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
689 skb
->nh
.raw
[optoff
+1]);
690 IP6_INC_STATS_BH(ipv6_skb_idev(skb
),
691 IPSTATS_MIB_INHDRERRORS
);
695 pkt_len
= ntohl(*(__be32
*)(skb
->nh
.raw
+optoff
+2));
696 if (pkt_len
<= IPV6_MAXPLEN
) {
697 IP6_INC_STATS_BH(ipv6_skb_idev(skb
), IPSTATS_MIB_INHDRERRORS
);
698 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
+2);
701 if (skb
->nh
.ipv6h
->payload_len
) {
702 IP6_INC_STATS_BH(ipv6_skb_idev(skb
), IPSTATS_MIB_INHDRERRORS
);
703 icmpv6_param_prob(skb
, ICMPV6_HDR_FIELD
, optoff
);
707 if (pkt_len
> skb
->len
- sizeof(struct ipv6hdr
)) {
708 IP6_INC_STATS_BH(ipv6_skb_idev(skb
), IPSTATS_MIB_INTRUNCATEDPKTS
);
712 if (pskb_trim_rcsum(skb
, pkt_len
+ sizeof(struct ipv6hdr
)))
722 static struct tlvtype_proc tlvprochopopt_lst
[] = {
724 .type
= IPV6_TLV_ROUTERALERT
,
728 .type
= IPV6_TLV_JUMBO
,
729 .func
= ipv6_hop_jumbo
,
734 int ipv6_parse_hopopts(struct sk_buff
**skbp
)
736 struct sk_buff
*skb
= *skbp
;
737 struct inet6_skb_parm
*opt
= IP6CB(skb
);
740 * skb->nh.raw is equal to skb->data, and
741 * skb->h.raw - skb->nh.raw is always equal to
742 * sizeof(struct ipv6hdr) by definition of
743 * hop-by-hop options.
745 if (!pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + 8) ||
746 !pskb_may_pull(skb
, sizeof(struct ipv6hdr
) + ((skb
->h
.raw
[1] + 1) << 3))) {
751 opt
->hop
= sizeof(struct ipv6hdr
);
752 if (ip6_parse_tlv(tlvprochopopt_lst
, skbp
)) {
754 skb
->h
.raw
+= (skb
->h
.raw
[1]+1)<<3;
756 opt
->nhoff
= sizeof(struct ipv6hdr
);
763 * Creating outbound headers.
765 * "build" functions work when skb is filled from head to tail (datagram)
766 * "push" functions work when headers are added from tail to head (tcp)
768 * In both cases we assume, that caller reserved enough room
772 static void ipv6_push_rthdr(struct sk_buff
*skb
, u8
*proto
,
773 struct ipv6_rt_hdr
*opt
,
774 struct in6_addr
**addr_p
)
776 struct rt0_hdr
*phdr
, *ihdr
;
779 ihdr
= (struct rt0_hdr
*) opt
;
781 phdr
= (struct rt0_hdr
*) skb_push(skb
, (ihdr
->rt_hdr
.hdrlen
+ 1) << 3);
782 memcpy(phdr
, ihdr
, sizeof(struct rt0_hdr
));
784 hops
= ihdr
->rt_hdr
.hdrlen
>> 1;
787 memcpy(phdr
->addr
, ihdr
->addr
+ 1,
788 (hops
- 1) * sizeof(struct in6_addr
));
790 ipv6_addr_copy(phdr
->addr
+ (hops
- 1), *addr_p
);
791 *addr_p
= ihdr
->addr
;
793 phdr
->rt_hdr
.nexthdr
= *proto
;
794 *proto
= NEXTHDR_ROUTING
;
797 static void ipv6_push_exthdr(struct sk_buff
*skb
, u8
*proto
, u8 type
, struct ipv6_opt_hdr
*opt
)
799 struct ipv6_opt_hdr
*h
= (struct ipv6_opt_hdr
*)skb_push(skb
, ipv6_optlen(opt
));
801 memcpy(h
, opt
, ipv6_optlen(opt
));
806 void ipv6_push_nfrag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
,
808 struct in6_addr
**daddr
)
811 ipv6_push_rthdr(skb
, proto
, opt
->srcrt
, daddr
);
813 * IPV6_RTHDRDSTOPTS is ignored
814 * unless IPV6_RTHDR is set (RFC3542).
817 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst0opt
);
820 ipv6_push_exthdr(skb
, proto
, NEXTHDR_HOP
, opt
->hopopt
);
823 void ipv6_push_frag_opts(struct sk_buff
*skb
, struct ipv6_txoptions
*opt
, u8
*proto
)
826 ipv6_push_exthdr(skb
, proto
, NEXTHDR_DEST
, opt
->dst1opt
);
829 struct ipv6_txoptions
*
830 ipv6_dup_options(struct sock
*sk
, struct ipv6_txoptions
*opt
)
832 struct ipv6_txoptions
*opt2
;
834 opt2
= sock_kmalloc(sk
, opt
->tot_len
, GFP_ATOMIC
);
836 long dif
= (char*)opt2
- (char*)opt
;
837 memcpy(opt2
, opt
, opt
->tot_len
);
839 *((char**)&opt2
->hopopt
) += dif
;
841 *((char**)&opt2
->dst0opt
) += dif
;
843 *((char**)&opt2
->dst1opt
) += dif
;
845 *((char**)&opt2
->srcrt
) += dif
;
850 EXPORT_SYMBOL_GPL(ipv6_dup_options
);
852 static int ipv6_renew_option(void *ohdr
,
853 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
,
855 struct ipv6_opt_hdr
**hdr
,
860 memcpy(*p
, ohdr
, ipv6_optlen((struct ipv6_opt_hdr
*)ohdr
));
861 *hdr
= (struct ipv6_opt_hdr
*)*p
;
862 *p
+= CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
));
866 if (copy_from_user(*p
, newopt
, newoptlen
))
868 *hdr
= (struct ipv6_opt_hdr
*)*p
;
869 if (ipv6_optlen(*(struct ipv6_opt_hdr
**)hdr
) > newoptlen
)
871 *p
+= CMSG_ALIGN(newoptlen
);
877 struct ipv6_txoptions
*
878 ipv6_renew_options(struct sock
*sk
, struct ipv6_txoptions
*opt
,
880 struct ipv6_opt_hdr __user
*newopt
, int newoptlen
)
884 struct ipv6_txoptions
*opt2
;
888 if (newtype
!= IPV6_HOPOPTS
&& opt
->hopopt
)
889 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->hopopt
));
890 if (newtype
!= IPV6_RTHDRDSTOPTS
&& opt
->dst0opt
)
891 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst0opt
));
892 if (newtype
!= IPV6_RTHDR
&& opt
->srcrt
)
893 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->srcrt
));
894 if (newtype
!= IPV6_DSTOPTS
&& opt
->dst1opt
)
895 tot_len
+= CMSG_ALIGN(ipv6_optlen(opt
->dst1opt
));
898 if (newopt
&& newoptlen
)
899 tot_len
+= CMSG_ALIGN(newoptlen
);
904 tot_len
+= sizeof(*opt2
);
905 opt2
= sock_kmalloc(sk
, tot_len
, GFP_ATOMIC
);
907 return ERR_PTR(-ENOBUFS
);
909 memset(opt2
, 0, tot_len
);
911 opt2
->tot_len
= tot_len
;
912 p
= (char *)(opt2
+ 1);
914 err
= ipv6_renew_option(opt
? opt
->hopopt
: NULL
, newopt
, newoptlen
,
915 newtype
!= IPV6_HOPOPTS
,
920 err
= ipv6_renew_option(opt
? opt
->dst0opt
: NULL
, newopt
, newoptlen
,
921 newtype
!= IPV6_RTHDRDSTOPTS
,
926 err
= ipv6_renew_option(opt
? opt
->srcrt
: NULL
, newopt
, newoptlen
,
927 newtype
!= IPV6_RTHDR
,
928 (struct ipv6_opt_hdr
**)&opt2
->srcrt
, &p
);
932 err
= ipv6_renew_option(opt
? opt
->dst1opt
: NULL
, newopt
, newoptlen
,
933 newtype
!= IPV6_DSTOPTS
,
938 opt2
->opt_nflen
= (opt2
->hopopt
? ipv6_optlen(opt2
->hopopt
) : 0) +
939 (opt2
->dst0opt
? ipv6_optlen(opt2
->dst0opt
) : 0) +
940 (opt2
->srcrt
? ipv6_optlen(opt2
->srcrt
) : 0);
941 opt2
->opt_flen
= (opt2
->dst1opt
? ipv6_optlen(opt2
->dst1opt
) : 0);
945 sock_kfree_s(sk
, opt2
, opt2
->tot_len
);
949 struct ipv6_txoptions
*ipv6_fixup_options(struct ipv6_txoptions
*opt_space
,
950 struct ipv6_txoptions
*opt
)
953 * ignore the dest before srcrt unless srcrt is being included.
956 if (opt
&& opt
->dst0opt
&& !opt
->srcrt
) {
957 if (opt_space
!= opt
) {
958 memcpy(opt_space
, opt
, sizeof(*opt_space
));
961 opt
->opt_nflen
-= ipv6_optlen(opt
->dst0opt
);