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