Linux 2.6.21.1
[linux/fpc-iii.git] / net / ipv6 / exthdrs.c
blob3205ec9ef4c0bc61ee1c4957ed14251db733edbc
1 /*
2 * Extension Header handling for IPv6
3 * Linux INET6 implementation
5 * Authors:
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.
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{}.
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>
35 #include <net/sock.h>
36 #include <net/snmp.h>
38 #include <net/ipv6.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
46 #include <net/xfrm.h>
47 #endif
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;
55 int len;
57 if (offset + 2 > packet_len)
58 goto bad;
59 hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
60 len = ((hdr->hdrlen + 1) << 3);
62 if (offset + len > packet_len)
63 goto bad;
65 offset += 2;
66 len -= 2;
68 while (len > 0) {
69 int opttype = skb->nh.raw[offset];
70 int optlen;
72 if (opttype == type)
73 return offset;
75 switch (opttype) {
76 case IPV6_TLV_PAD0:
77 optlen = 1;
78 break;
79 default:
80 optlen = skb->nh.raw[offset + 1] + 2;
81 if (optlen > len)
82 goto bad;
83 break;
85 offset += optlen;
86 len -= optlen;
88 /* not_found */
89 bad:
90 return -1;
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 {
102 int type;
103 int (*func)(struct sk_buff **skbp, int offset);
106 /*********************
107 Generic functions
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) {
117 case 0: /* ignore */
118 return 1;
120 case 1: /* drop packet */
121 break;
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))
128 break;
129 case 2: /* send ICMP PARM PROB regardless and drop packet */
130 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
131 return 0;
134 kfree_skb(skb);
135 return 0;
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))
148 goto bad;
150 off += 2;
151 len -= 2;
153 while (len > 0) {
154 int optlen = skb->nh.raw[off+1]+2;
156 switch (skb->nh.raw[off]) {
157 case IPV6_TLV_PAD0:
158 optlen = 1;
159 break;
161 case IPV6_TLV_PADN:
162 break;
164 default: /* Other TLV code so scan list */
165 if (optlen > len)
166 goto bad;
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
171 func(). */
172 if (curr->func(skbp, off) == 0)
173 return 0;
174 break;
177 if (curr->type < 0) {
178 if (ip6_tlvopt_unknown(skbp, off) == 0)
179 return 0;
181 break;
183 off += optlen;
184 len -= optlen;
186 if (len == 0)
187 return 1;
188 bad:
189 kfree_skb(skb);
190 return 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;
205 int ret;
207 if (opt->dsthao) {
208 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
209 goto discard;
211 opt->dsthao = opt->dst1;
212 opt->dst1 = 0;
214 hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
216 if (hao->length != 16) {
217 LIMIT_NETDEBUG(
218 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
219 goto discard;
222 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
223 LIMIT_NETDEBUG(
224 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
225 goto discard;
228 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
229 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
230 if (unlikely(ret < 0))
231 goto discard;
233 if (skb_cloned(skb)) {
234 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
235 struct inet6_skb_parm *opt2;
237 if (skb2 == NULL)
238 goto discard;
240 opt2 = IP6CB(skb2);
241 memcpy(opt2, opt, sizeof(*opt2));
243 kfree_skb(skb);
245 /* update all variable using below by copied skbuff */
246 *skbp = skb = skb2;
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);
261 return 1;
263 discard:
264 kfree_skb(skb);
265 return 0;
267 #endif
269 static struct tlvtype_proc tlvprocdestopt_lst[] = {
270 #ifdef CONFIG_IPV6_MIP6
272 .type = IPV6_TLV_HAO,
273 .func = ipv6_dest_hao,
275 #endif
276 {-1, NULL}
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
284 __u16 dstbuf;
285 #endif
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);
292 kfree_skb(skb);
293 return -1;
296 opt->lastopt = skb->h.raw - skb->nh.raw;
297 opt->dst1 = skb->h.raw - skb->nh.raw;
298 #ifdef CONFIG_IPV6_MIP6
299 dstbuf = opt->dst1;
300 #endif
302 dst = dst_clone(skb->dst);
303 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
304 dst_release(dst);
305 skb = *skbp;
306 skb->h.raw += ((skb->h.raw[1]+1)<<3);
307 opt = IP6CB(skb);
308 #ifdef CONFIG_IPV6_MIP6
309 opt->nhoff = dstbuf;
310 #else
311 opt->nhoff = opt->dst1;
312 #endif
313 return 1;
316 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
317 dst_release(dst);
318 return -1;
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;
340 kfree_skb(skb);
341 return 0;
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 /********************************
356 Routing header.
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;
366 int n, i;
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)) {
373 kfree_skb(skb);
374 return -1;
376 if (idev->cnf.accept_source_route < 0) {
377 in6_dev_put(idev);
378 kfree_skb(skb);
379 return -1;
382 if (accept_source_route > idev->cnf.accept_source_route)
383 accept_source_route = idev->cnf.accept_source_route;
385 in6_dev_put(idev);
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);
391 kfree_skb(skb);
392 return -1;
395 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
397 switch (hdr->type) {
398 #ifdef CONFIG_IPV6_MIP6
399 case IPV6_SRCRT_TYPE_2:
400 break;
401 #endif
402 case IPV6_SRCRT_TYPE_0:
403 if (accept_source_route > 0)
404 break;
405 kfree_skb(skb);
406 return -1;
407 default:
408 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
409 IPSTATS_MIB_INHDRERRORS);
410 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
411 return -1;
414 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
415 skb->pkt_type != PACKET_HOST) {
416 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
417 IPSTATS_MIB_INADDRERRORS);
418 kfree_skb(skb);
419 return -1;
422 looped_back:
423 if (hdr->segments_left == 0) {
424 switch (hdr->type) {
425 #ifdef CONFIG_IPV6_MIP6
426 case IPV6_SRCRT_TYPE_2:
427 /* Silently discard type 2 header unless it was
428 * processed by own
430 if (!addr) {
431 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
432 IPSTATS_MIB_INADDRERRORS);
433 kfree_skb(skb);
434 return -1;
436 break;
437 #endif
438 default:
439 break;
442 opt->lastopt = skb->h.raw - skb->nh.raw;
443 opt->srcrt = skb->h.raw - skb->nh.raw;
444 skb->h.raw += (hdr->hdrlen + 1) << 3;
445 opt->dst0 = opt->dst1;
446 opt->dst1 = 0;
447 opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
448 return 1;
451 switch (hdr->type) {
452 case IPV6_SRCRT_TYPE_0:
453 if (hdr->hdrlen & 0x01) {
454 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
455 IPSTATS_MIB_INHDRERRORS);
456 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
457 return -1;
459 break;
460 #ifdef CONFIG_IPV6_MIP6
461 case IPV6_SRCRT_TYPE_2:
462 /* Silently discard invalid RTH type 2 */
463 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
464 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
465 IPSTATS_MIB_INHDRERRORS);
466 kfree_skb(skb);
467 return -1;
469 break;
470 #endif
474 * This is the routing header forwarding algorithm from
475 * RFC 2460, page 16.
478 n = hdr->hdrlen >> 1;
480 if (hdr->segments_left > n) {
481 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
482 IPSTATS_MIB_INHDRERRORS);
483 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
484 return -1;
487 /* We are about to mangle packet header. Be careful!
488 Do not damage packets queued somewhere.
490 if (skb_cloned(skb)) {
491 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
492 /* the copy is a forwarded packet */
493 if (skb2 == NULL) {
494 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
495 IPSTATS_MIB_OUTDISCARDS);
496 kfree_skb(skb);
497 return -1;
499 kfree_skb(skb);
500 *skbp = skb = skb2;
501 opt = IP6CB(skb2);
502 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
505 if (skb->ip_summed == CHECKSUM_COMPLETE)
506 skb->ip_summed = CHECKSUM_NONE;
508 i = n - --hdr->segments_left;
510 rthdr = (struct rt0_hdr *) hdr;
511 addr = rthdr->addr;
512 addr += i - 1;
514 switch (hdr->type) {
515 #ifdef CONFIG_IPV6_MIP6
516 case IPV6_SRCRT_TYPE_2:
517 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
518 (xfrm_address_t *)&skb->nh.ipv6h->saddr,
519 IPPROTO_ROUTING) < 0) {
520 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
521 IPSTATS_MIB_INADDRERRORS);
522 kfree_skb(skb);
523 return -1;
525 if (!ipv6_chk_home_addr(addr)) {
526 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
527 IPSTATS_MIB_INADDRERRORS);
528 kfree_skb(skb);
529 return -1;
531 break;
532 #endif
533 default:
534 break;
537 if (ipv6_addr_is_multicast(addr)) {
538 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
539 IPSTATS_MIB_INADDRERRORS);
540 kfree_skb(skb);
541 return -1;
544 ipv6_addr_copy(&daddr, addr);
545 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
546 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
548 dst_release(xchg(&skb->dst, NULL));
549 ip6_route_input(skb);
550 if (skb->dst->error) {
551 skb_push(skb, skb->data - skb->nh.raw);
552 dst_input(skb);
553 return -1;
556 if (skb->dst->dev->flags&IFF_LOOPBACK) {
557 if (skb->nh.ipv6h->hop_limit <= 1) {
558 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
559 IPSTATS_MIB_INHDRERRORS);
560 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
561 0, skb->dev);
562 kfree_skb(skb);
563 return -1;
565 skb->nh.ipv6h->hop_limit--;
566 goto looped_back;
569 skb_push(skb, skb->data - skb->nh.raw);
570 dst_input(skb);
571 return -1;
574 static struct inet6_protocol rthdr_protocol = {
575 .handler = ipv6_rthdr_rcv,
576 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
579 void __init ipv6_rthdr_init(void)
581 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
582 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
586 This function inverts received rthdr.
587 NOTE: specs allow to make it automatically only if
588 packet authenticated.
590 I will not discuss it here (though, I am really pissed off at
591 this stupid requirement making rthdr idea useless)
593 Actually, it creates severe problems for us.
594 Embryonic requests has no associated sockets,
595 so that user have no control over it and
596 cannot not only to set reply options, but
597 even to know, that someone wants to connect
598 without success. :-(
600 For now we need to test the engine, so that I created
601 temporary (or permanent) backdoor.
602 If listening socket set IPV6_RTHDR to 2, then we invert header.
603 --ANK (980729)
606 struct ipv6_txoptions *
607 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
609 /* Received rthdr:
611 [ H1 -> H2 -> ... H_prev ] daddr=ME
613 Inverted result:
614 [ H_prev -> ... -> H1 ] daddr =sender
616 Note, that IP output engine will rewrite this rthdr
617 by rotating it left by one addr.
620 int n, i;
621 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
622 struct rt0_hdr *irthdr;
623 struct ipv6_txoptions *opt;
624 int hdrlen = ipv6_optlen(hdr);
626 if (hdr->segments_left ||
627 hdr->type != IPV6_SRCRT_TYPE_0 ||
628 hdr->hdrlen & 0x01)
629 return NULL;
631 n = hdr->hdrlen >> 1;
632 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
633 if (opt == NULL)
634 return NULL;
635 memset(opt, 0, sizeof(*opt));
636 opt->tot_len = sizeof(*opt) + hdrlen;
637 opt->srcrt = (void*)(opt+1);
638 opt->opt_nflen = hdrlen;
640 memcpy(opt->srcrt, hdr, sizeof(*hdr));
641 irthdr = (struct rt0_hdr*)opt->srcrt;
642 irthdr->reserved = 0;
643 opt->srcrt->segments_left = n;
644 for (i=0; i<n; i++)
645 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
646 return opt;
649 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
651 /**********************************
652 Hop-by-hop options.
653 **********************************/
655 /* Router Alert as of RFC 2711 */
657 static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
659 struct sk_buff *skb = *skbp;
661 if (skb->nh.raw[optoff+1] == 2) {
662 IP6CB(skb)->ra = optoff;
663 return 1;
665 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
666 skb->nh.raw[optoff+1]);
667 kfree_skb(skb);
668 return 0;
671 /* Jumbo payload */
673 static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
675 struct sk_buff *skb = *skbp;
676 u32 pkt_len;
678 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
679 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
680 skb->nh.raw[optoff+1]);
681 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
682 IPSTATS_MIB_INHDRERRORS);
683 goto drop;
686 pkt_len = ntohl(*(__be32*)(skb->nh.raw+optoff+2));
687 if (pkt_len <= IPV6_MAXPLEN) {
688 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
689 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
690 return 0;
692 if (skb->nh.ipv6h->payload_len) {
693 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
694 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
695 return 0;
698 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
699 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
700 goto drop;
703 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
704 goto drop;
706 return 1;
708 drop:
709 kfree_skb(skb);
710 return 0;
713 static struct tlvtype_proc tlvprochopopt_lst[] = {
715 .type = IPV6_TLV_ROUTERALERT,
716 .func = ipv6_hop_ra,
719 .type = IPV6_TLV_JUMBO,
720 .func = ipv6_hop_jumbo,
722 { -1, }
725 int ipv6_parse_hopopts(struct sk_buff **skbp)
727 struct sk_buff *skb = *skbp;
728 struct inet6_skb_parm *opt = IP6CB(skb);
731 * skb->nh.raw is equal to skb->data, and
732 * skb->h.raw - skb->nh.raw is always equal to
733 * sizeof(struct ipv6hdr) by definition of
734 * hop-by-hop options.
736 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
737 !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
738 kfree_skb(skb);
739 return -1;
742 opt->hop = sizeof(struct ipv6hdr);
743 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
744 skb = *skbp;
745 skb->h.raw += (skb->h.raw[1]+1)<<3;
746 opt = IP6CB(skb);
747 opt->nhoff = sizeof(struct ipv6hdr);
748 return 1;
750 return -1;
754 * Creating outbound headers.
756 * "build" functions work when skb is filled from head to tail (datagram)
757 * "push" functions work when headers are added from tail to head (tcp)
759 * In both cases we assume, that caller reserved enough room
760 * for headers.
763 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
764 struct ipv6_rt_hdr *opt,
765 struct in6_addr **addr_p)
767 struct rt0_hdr *phdr, *ihdr;
768 int hops;
770 ihdr = (struct rt0_hdr *) opt;
772 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
773 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
775 hops = ihdr->rt_hdr.hdrlen >> 1;
777 if (hops > 1)
778 memcpy(phdr->addr, ihdr->addr + 1,
779 (hops - 1) * sizeof(struct in6_addr));
781 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
782 *addr_p = ihdr->addr;
784 phdr->rt_hdr.nexthdr = *proto;
785 *proto = NEXTHDR_ROUTING;
788 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
790 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
792 memcpy(h, opt, ipv6_optlen(opt));
793 h->nexthdr = *proto;
794 *proto = type;
797 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
798 u8 *proto,
799 struct in6_addr **daddr)
801 if (opt->srcrt) {
802 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
804 * IPV6_RTHDRDSTOPTS is ignored
805 * unless IPV6_RTHDR is set (RFC3542).
807 if (opt->dst0opt)
808 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
810 if (opt->hopopt)
811 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
814 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
816 if (opt->dst1opt)
817 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
820 struct ipv6_txoptions *
821 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
823 struct ipv6_txoptions *opt2;
825 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
826 if (opt2) {
827 long dif = (char*)opt2 - (char*)opt;
828 memcpy(opt2, opt, opt->tot_len);
829 if (opt2->hopopt)
830 *((char**)&opt2->hopopt) += dif;
831 if (opt2->dst0opt)
832 *((char**)&opt2->dst0opt) += dif;
833 if (opt2->dst1opt)
834 *((char**)&opt2->dst1opt) += dif;
835 if (opt2->srcrt)
836 *((char**)&opt2->srcrt) += dif;
838 return opt2;
841 EXPORT_SYMBOL_GPL(ipv6_dup_options);
843 static int ipv6_renew_option(void *ohdr,
844 struct ipv6_opt_hdr __user *newopt, int newoptlen,
845 int inherit,
846 struct ipv6_opt_hdr **hdr,
847 char **p)
849 if (inherit) {
850 if (ohdr) {
851 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
852 *hdr = (struct ipv6_opt_hdr *)*p;
853 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
855 } else {
856 if (newopt) {
857 if (copy_from_user(*p, newopt, newoptlen))
858 return -EFAULT;
859 *hdr = (struct ipv6_opt_hdr *)*p;
860 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
861 return -EINVAL;
862 *p += CMSG_ALIGN(newoptlen);
865 return 0;
868 struct ipv6_txoptions *
869 ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
870 int newtype,
871 struct ipv6_opt_hdr __user *newopt, int newoptlen)
873 int tot_len = 0;
874 char *p;
875 struct ipv6_txoptions *opt2;
876 int err;
878 if (opt) {
879 if (newtype != IPV6_HOPOPTS && opt->hopopt)
880 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
881 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
882 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
883 if (newtype != IPV6_RTHDR && opt->srcrt)
884 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
885 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
886 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
889 if (newopt && newoptlen)
890 tot_len += CMSG_ALIGN(newoptlen);
892 if (!tot_len)
893 return NULL;
895 tot_len += sizeof(*opt2);
896 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
897 if (!opt2)
898 return ERR_PTR(-ENOBUFS);
900 memset(opt2, 0, tot_len);
902 opt2->tot_len = tot_len;
903 p = (char *)(opt2 + 1);
905 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
906 newtype != IPV6_HOPOPTS,
907 &opt2->hopopt, &p);
908 if (err)
909 goto out;
911 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
912 newtype != IPV6_RTHDRDSTOPTS,
913 &opt2->dst0opt, &p);
914 if (err)
915 goto out;
917 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
918 newtype != IPV6_RTHDR,
919 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
920 if (err)
921 goto out;
923 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
924 newtype != IPV6_DSTOPTS,
925 &opt2->dst1opt, &p);
926 if (err)
927 goto out;
929 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
930 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
931 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
932 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
934 return opt2;
935 out:
936 sock_kfree_s(sk, opt2, opt2->tot_len);
937 return ERR_PTR(err);
940 struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
941 struct ipv6_txoptions *opt)
944 * ignore the dest before srcrt unless srcrt is being included.
945 * --yoshfuji
947 if (opt && opt->dst0opt && !opt->srcrt) {
948 if (opt_space != opt) {
949 memcpy(opt_space, opt, sizeof(*opt_space));
950 opt = opt_space;
952 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
953 opt->dst0opt = NULL;
956 return opt;