ACPI: thinkpad-acpi: add a safety net for TPEC fan control mode
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / net / ipv6 / exthdrs.c
blobde96e1a555d5c2925394b2ce4654d5fc67356469
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/sched.h>
31 #include <linux/net.h>
32 #include <linux/netdevice.h>
33 #include <linux/in6.h>
34 #include <linux/icmpv6.h>
36 #include <net/sock.h>
37 #include <net/snmp.h>
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>
46 #ifdef CONFIG_IPV6_MIP6
47 #include <net/xfrm.h>
48 #endif
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;
56 int len;
58 if (offset + 2 > packet_len)
59 goto bad;
60 hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
61 len = ((hdr->hdrlen + 1) << 3);
63 if (offset + len > packet_len)
64 goto bad;
66 offset += 2;
67 len -= 2;
69 while (len > 0) {
70 int opttype = skb->nh.raw[offset];
71 int optlen;
73 if (opttype == type)
74 return offset;
76 switch (opttype) {
77 case IPV6_TLV_PAD0:
78 optlen = 1;
79 break;
80 default:
81 optlen = skb->nh.raw[offset + 1] + 2;
82 if (optlen > len)
83 goto bad;
84 break;
86 offset += optlen;
87 len -= optlen;
89 /* not_found */
90 bad:
91 return -1;
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 {
103 int type;
104 int (*func)(struct sk_buff **skbp, int offset);
107 /*********************
108 Generic functions
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) {
118 case 0: /* ignore */
119 return 1;
121 case 1: /* drop packet */
122 break;
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))
129 break;
130 case 2: /* send ICMP PARM PROB regardless and drop packet */
131 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
132 return 0;
135 kfree_skb(skb);
136 return 0;
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))
149 goto bad;
151 off += 2;
152 len -= 2;
154 while (len > 0) {
155 int optlen = skb->nh.raw[off+1]+2;
157 switch (skb->nh.raw[off]) {
158 case IPV6_TLV_PAD0:
159 optlen = 1;
160 break;
162 case IPV6_TLV_PADN:
163 break;
165 default: /* Other TLV code so scan list */
166 if (optlen > len)
167 goto bad;
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
172 func(). */
173 if (curr->func(skbp, off) == 0)
174 return 0;
175 break;
178 if (curr->type < 0) {
179 if (ip6_tlvopt_unknown(skbp, off) == 0)
180 return 0;
182 break;
184 off += optlen;
185 len -= optlen;
187 if (len == 0)
188 return 1;
189 bad:
190 kfree_skb(skb);
191 return 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;
206 int ret;
208 if (opt->dsthao) {
209 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
210 goto discard;
212 opt->dsthao = opt->dst1;
213 opt->dst1 = 0;
215 hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
217 if (hao->length != 16) {
218 LIMIT_NETDEBUG(
219 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
220 goto discard;
223 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
224 LIMIT_NETDEBUG(
225 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
226 goto discard;
229 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
230 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
231 if (unlikely(ret < 0))
232 goto discard;
234 if (skb_cloned(skb)) {
235 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
236 struct inet6_skb_parm *opt2;
238 if (skb2 == NULL)
239 goto discard;
241 opt2 = IP6CB(skb2);
242 memcpy(opt2, opt, sizeof(*opt2));
244 kfree_skb(skb);
246 /* update all variable using below by copied skbuff */
247 *skbp = skb = skb2;
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);
262 return 1;
264 discard:
265 kfree_skb(skb);
266 return 0;
268 #endif
270 static struct tlvtype_proc tlvprocdestopt_lst[] = {
271 #ifdef CONFIG_IPV6_MIP6
273 .type = IPV6_TLV_HAO,
274 .func = ipv6_dest_hao,
276 #endif
277 {-1, NULL}
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
285 __u16 dstbuf;
286 #endif
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);
293 kfree_skb(skb);
294 return -1;
297 opt->lastopt = skb->h.raw - skb->nh.raw;
298 opt->dst1 = skb->h.raw - skb->nh.raw;
299 #ifdef CONFIG_IPV6_MIP6
300 dstbuf = opt->dst1;
301 #endif
303 dst = dst_clone(skb->dst);
304 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
305 dst_release(dst);
306 skb = *skbp;
307 skb->h.raw += ((skb->h.raw[1]+1)<<3);
308 opt = IP6CB(skb);
309 #ifdef CONFIG_IPV6_MIP6
310 opt->nhoff = dstbuf;
311 #else
312 opt->nhoff = opt->dst1;
313 #endif
314 return 1;
317 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
318 dst_release(dst);
319 return -1;
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;
341 kfree_skb(skb);
342 return 0;
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 /********************************
357 Routing header.
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;
367 int n, i;
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)) {
374 kfree_skb(skb);
375 return -1;
377 if (idev->cnf.accept_source_route < 0) {
378 in6_dev_put(idev);
379 kfree_skb(skb);
380 return -1;
383 if (accept_source_route > idev->cnf.accept_source_route)
384 accept_source_route = idev->cnf.accept_source_route;
386 in6_dev_put(idev);
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);
392 kfree_skb(skb);
393 return -1;
396 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
398 switch (hdr->type) {
399 #ifdef CONFIG_IPV6_MIP6
400 case IPV6_SRCRT_TYPE_2:
401 break;
402 #endif
403 case IPV6_SRCRT_TYPE_0:
404 if (accept_source_route > 0)
405 break;
406 kfree_skb(skb);
407 return -1;
408 default:
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);
412 return -1;
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);
419 kfree_skb(skb);
420 return -1;
423 looped_back:
424 if (hdr->segments_left == 0) {
425 switch (hdr->type) {
426 #ifdef CONFIG_IPV6_MIP6
427 case IPV6_SRCRT_TYPE_2:
428 /* Silently discard type 2 header unless it was
429 * processed by own
431 if (!addr) {
432 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
433 IPSTATS_MIB_INADDRERRORS);
434 kfree_skb(skb);
435 return -1;
437 break;
438 #endif
439 default:
440 break;
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;
447 opt->dst1 = 0;
448 opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
449 return 1;
452 switch (hdr->type) {
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);
458 return -1;
460 break;
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);
467 kfree_skb(skb);
468 return -1;
470 break;
471 #endif
475 * This is the routing header forwarding algorithm from
476 * RFC 2460, page 16.
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);
485 return -1;
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 */
494 if (skb2 == NULL) {
495 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
496 IPSTATS_MIB_OUTDISCARDS);
497 kfree_skb(skb);
498 return -1;
500 kfree_skb(skb);
501 *skbp = skb = skb2;
502 opt = IP6CB(skb2);
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;
512 addr = rthdr->addr;
513 addr += i - 1;
515 switch (hdr->type) {
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);
523 kfree_skb(skb);
524 return -1;
526 if (!ipv6_chk_home_addr(addr)) {
527 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
528 IPSTATS_MIB_INADDRERRORS);
529 kfree_skb(skb);
530 return -1;
532 break;
533 #endif
534 default:
535 break;
538 if (ipv6_addr_is_multicast(addr)) {
539 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
540 IPSTATS_MIB_INADDRERRORS);
541 kfree_skb(skb);
542 return -1;
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);
553 dst_input(skb);
554 return -1;
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,
562 0, skb->dev);
563 kfree_skb(skb);
564 return -1;
566 skb->nh.ipv6h->hop_limit--;
567 goto looped_back;
570 skb_push(skb, skb->data - skb->nh.raw);
571 dst_input(skb);
572 return -1;
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
599 without success. :-(
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.
604 --ANK (980729)
607 struct ipv6_txoptions *
608 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
610 /* Received rthdr:
612 [ H1 -> H2 -> ... H_prev ] daddr=ME
614 Inverted result:
615 [ H_prev -> ... -> H1 ] daddr =sender
617 Note, that IP output engine will rewrite this rthdr
618 by rotating it left by one addr.
621 int n, i;
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 ||
629 hdr->hdrlen & 0x01)
630 return NULL;
632 n = hdr->hdrlen >> 1;
633 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
634 if (opt == NULL)
635 return NULL;
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;
645 for (i=0; i<n; i++)
646 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
647 return opt;
650 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
652 /**********************************
653 Hop-by-hop options.
654 **********************************/
656 /* Router Alert as of RFC 2711 */
658 static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
660 struct sk_buff *skb = *skbp;
662 if (skb->nh.raw[optoff+1] == 2) {
663 IP6CB(skb)->ra = optoff;
664 return 1;
666 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
667 skb->nh.raw[optoff+1]);
668 kfree_skb(skb);
669 return 0;
672 /* Jumbo payload */
674 static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
676 struct sk_buff *skb = *skbp;
677 u32 pkt_len;
679 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
680 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
681 skb->nh.raw[optoff+1]);
682 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
683 IPSTATS_MIB_INHDRERRORS);
684 goto drop;
687 pkt_len = ntohl(*(__be32*)(skb->nh.raw+optoff+2));
688 if (pkt_len <= IPV6_MAXPLEN) {
689 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
690 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
691 return 0;
693 if (skb->nh.ipv6h->payload_len) {
694 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
695 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
696 return 0;
699 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
700 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
701 goto drop;
704 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
705 goto drop;
707 return 1;
709 drop:
710 kfree_skb(skb);
711 return 0;
714 static struct tlvtype_proc tlvprochopopt_lst[] = {
716 .type = IPV6_TLV_ROUTERALERT,
717 .func = ipv6_hop_ra,
720 .type = IPV6_TLV_JUMBO,
721 .func = ipv6_hop_jumbo,
723 { -1, }
726 int ipv6_parse_hopopts(struct sk_buff **skbp)
728 struct sk_buff *skb = *skbp;
729 struct inet6_skb_parm *opt = IP6CB(skb);
732 * skb->nh.raw is equal to skb->data, and
733 * skb->h.raw - skb->nh.raw is always equal to
734 * sizeof(struct ipv6hdr) by definition of
735 * hop-by-hop options.
737 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
738 !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
739 kfree_skb(skb);
740 return -1;
743 opt->hop = sizeof(struct ipv6hdr);
744 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
745 skb = *skbp;
746 skb->h.raw += (skb->h.raw[1]+1)<<3;
747 opt = IP6CB(skb);
748 opt->nhoff = sizeof(struct ipv6hdr);
749 return 1;
751 return -1;
755 * Creating outbound headers.
757 * "build" functions work when skb is filled from head to tail (datagram)
758 * "push" functions work when headers are added from tail to head (tcp)
760 * In both cases we assume, that caller reserved enough room
761 * for headers.
764 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
765 struct ipv6_rt_hdr *opt,
766 struct in6_addr **addr_p)
768 struct rt0_hdr *phdr, *ihdr;
769 int hops;
771 ihdr = (struct rt0_hdr *) opt;
773 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
774 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
776 hops = ihdr->rt_hdr.hdrlen >> 1;
778 if (hops > 1)
779 memcpy(phdr->addr, ihdr->addr + 1,
780 (hops - 1) * sizeof(struct in6_addr));
782 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
783 *addr_p = ihdr->addr;
785 phdr->rt_hdr.nexthdr = *proto;
786 *proto = NEXTHDR_ROUTING;
789 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
791 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
793 memcpy(h, opt, ipv6_optlen(opt));
794 h->nexthdr = *proto;
795 *proto = type;
798 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
799 u8 *proto,
800 struct in6_addr **daddr)
802 if (opt->srcrt) {
803 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
805 * IPV6_RTHDRDSTOPTS is ignored
806 * unless IPV6_RTHDR is set (RFC3542).
808 if (opt->dst0opt)
809 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
811 if (opt->hopopt)
812 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
815 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
817 if (opt->dst1opt)
818 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
821 struct ipv6_txoptions *
822 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
824 struct ipv6_txoptions *opt2;
826 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
827 if (opt2) {
828 long dif = (char*)opt2 - (char*)opt;
829 memcpy(opt2, opt, opt->tot_len);
830 if (opt2->hopopt)
831 *((char**)&opt2->hopopt) += dif;
832 if (opt2->dst0opt)
833 *((char**)&opt2->dst0opt) += dif;
834 if (opt2->dst1opt)
835 *((char**)&opt2->dst1opt) += dif;
836 if (opt2->srcrt)
837 *((char**)&opt2->srcrt) += dif;
839 return opt2;
842 EXPORT_SYMBOL_GPL(ipv6_dup_options);
844 static int ipv6_renew_option(void *ohdr,
845 struct ipv6_opt_hdr __user *newopt, int newoptlen,
846 int inherit,
847 struct ipv6_opt_hdr **hdr,
848 char **p)
850 if (inherit) {
851 if (ohdr) {
852 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
853 *hdr = (struct ipv6_opt_hdr *)*p;
854 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
856 } else {
857 if (newopt) {
858 if (copy_from_user(*p, newopt, newoptlen))
859 return -EFAULT;
860 *hdr = (struct ipv6_opt_hdr *)*p;
861 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
862 return -EINVAL;
863 *p += CMSG_ALIGN(newoptlen);
866 return 0;
869 struct ipv6_txoptions *
870 ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
871 int newtype,
872 struct ipv6_opt_hdr __user *newopt, int newoptlen)
874 int tot_len = 0;
875 char *p;
876 struct ipv6_txoptions *opt2;
877 int err;
879 if (opt) {
880 if (newtype != IPV6_HOPOPTS && opt->hopopt)
881 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
882 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
883 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
884 if (newtype != IPV6_RTHDR && opt->srcrt)
885 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
886 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
887 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
890 if (newopt && newoptlen)
891 tot_len += CMSG_ALIGN(newoptlen);
893 if (!tot_len)
894 return NULL;
896 tot_len += sizeof(*opt2);
897 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
898 if (!opt2)
899 return ERR_PTR(-ENOBUFS);
901 memset(opt2, 0, tot_len);
903 opt2->tot_len = tot_len;
904 p = (char *)(opt2 + 1);
906 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
907 newtype != IPV6_HOPOPTS,
908 &opt2->hopopt, &p);
909 if (err)
910 goto out;
912 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
913 newtype != IPV6_RTHDRDSTOPTS,
914 &opt2->dst0opt, &p);
915 if (err)
916 goto out;
918 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
919 newtype != IPV6_RTHDR,
920 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
921 if (err)
922 goto out;
924 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
925 newtype != IPV6_DSTOPTS,
926 &opt2->dst1opt, &p);
927 if (err)
928 goto out;
930 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
931 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
932 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
933 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
935 return opt2;
936 out:
937 sock_kfree_s(sk, opt2, opt2->tot_len);
938 return ERR_PTR(err);
941 struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
942 struct ipv6_txoptions *opt)
945 * ignore the dest before srcrt unless srcrt is being included.
946 * --yoshfuji
948 if (opt && opt->dst0opt && !opt->srcrt) {
949 if (opt_space != opt) {
950 memcpy(opt_space, opt, sizeof(*opt_space));
951 opt = opt_space;
953 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
954 opt->dst0opt = NULL;
957 return opt;