ACPI: thinkpad-acpi: update MAINTAINERS
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / net / ipv6 / exthdrs.c
blob82a344493502ee3473b575c3fe78800ebcc11bea
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 **********************************/
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;
672 return 1;
674 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
675 skb->nh.raw[optoff+1]);
676 kfree_skb(skb);
677 return 0;
680 /* Jumbo payload */
682 static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
684 struct sk_buff *skb = *skbp;
685 u32 pkt_len;
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);
692 goto drop;
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);
699 return 0;
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);
704 return 0;
707 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
708 IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
709 goto drop;
712 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
713 goto drop;
715 return 1;
717 drop:
718 kfree_skb(skb);
719 return 0;
722 static struct tlvtype_proc tlvprochopopt_lst[] = {
724 .type = IPV6_TLV_ROUTERALERT,
725 .func = ipv6_hop_ra,
728 .type = IPV6_TLV_JUMBO,
729 .func = ipv6_hop_jumbo,
731 { -1, }
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))) {
747 kfree_skb(skb);
748 return -1;
751 opt->hop = sizeof(struct ipv6hdr);
752 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
753 skb = *skbp;
754 skb->h.raw += (skb->h.raw[1]+1)<<3;
755 opt = IP6CB(skb);
756 opt->nhoff = sizeof(struct ipv6hdr);
757 return 1;
759 return -1;
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
769 * for headers.
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;
777 int hops;
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;
786 if (hops > 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));
802 h->nexthdr = *proto;
803 *proto = type;
806 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
807 u8 *proto,
808 struct in6_addr **daddr)
810 if (opt->srcrt) {
811 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
813 * IPV6_RTHDRDSTOPTS is ignored
814 * unless IPV6_RTHDR is set (RFC3542).
816 if (opt->dst0opt)
817 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
819 if (opt->hopopt)
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)
825 if (opt->dst1opt)
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);
835 if (opt2) {
836 long dif = (char*)opt2 - (char*)opt;
837 memcpy(opt2, opt, opt->tot_len);
838 if (opt2->hopopt)
839 *((char**)&opt2->hopopt) += dif;
840 if (opt2->dst0opt)
841 *((char**)&opt2->dst0opt) += dif;
842 if (opt2->dst1opt)
843 *((char**)&opt2->dst1opt) += dif;
844 if (opt2->srcrt)
845 *((char**)&opt2->srcrt) += dif;
847 return opt2;
850 EXPORT_SYMBOL_GPL(ipv6_dup_options);
852 static int ipv6_renew_option(void *ohdr,
853 struct ipv6_opt_hdr __user *newopt, int newoptlen,
854 int inherit,
855 struct ipv6_opt_hdr **hdr,
856 char **p)
858 if (inherit) {
859 if (ohdr) {
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));
864 } else {
865 if (newopt) {
866 if (copy_from_user(*p, newopt, newoptlen))
867 return -EFAULT;
868 *hdr = (struct ipv6_opt_hdr *)*p;
869 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
870 return -EINVAL;
871 *p += CMSG_ALIGN(newoptlen);
874 return 0;
877 struct ipv6_txoptions *
878 ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
879 int newtype,
880 struct ipv6_opt_hdr __user *newopt, int newoptlen)
882 int tot_len = 0;
883 char *p;
884 struct ipv6_txoptions *opt2;
885 int err;
887 if (opt) {
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);
901 if (!tot_len)
902 return NULL;
904 tot_len += sizeof(*opt2);
905 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
906 if (!opt2)
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,
916 &opt2->hopopt, &p);
917 if (err)
918 goto out;
920 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
921 newtype != IPV6_RTHDRDSTOPTS,
922 &opt2->dst0opt, &p);
923 if (err)
924 goto out;
926 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
927 newtype != IPV6_RTHDR,
928 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
929 if (err)
930 goto out;
932 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
933 newtype != IPV6_DSTOPTS,
934 &opt2->dst1opt, &p);
935 if (err)
936 goto out;
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);
943 return opt2;
944 out:
945 sock_kfree_s(sk, opt2, opt2->tot_len);
946 return ERR_PTR(err);
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.
954 * --yoshfuji
956 if (opt && opt->dst0opt && !opt->srcrt) {
957 if (opt_space != opt) {
958 memcpy(opt_space, opt, sizeof(*opt_space));
959 opt = opt_space;
961 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
962 opt->dst0opt = NULL;
965 return opt;