allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / net / ipv6 / exthdrs.c
blob38a3d32963291cf49438933aba01bfc67f862a1b
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 const unsigned char *nh = skb_network_header(skb);
54 int packet_len = skb->tail - skb->network_header;
55 struct ipv6_opt_hdr *hdr;
56 int len;
58 if (offset + 2 > packet_len)
59 goto bad;
60 hdr = (struct ipv6_opt_hdr *)(nh + 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 = nh[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 = nh[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 *skb, 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 *skb, int optoff)
115 switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
116 case 0: /* ignore */
117 return 1;
119 case 1: /* drop packet */
120 break;
122 case 3: /* Send ICMP if not a multicast address and drop packet */
123 /* Actually, it is redundant check. icmp_send
124 will recheck in any case.
126 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
127 break;
128 case 2: /* send ICMP PARM PROB regardless and drop packet */
129 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
130 return 0;
133 kfree_skb(skb);
134 return 0;
137 /* Parse tlv encoded option header (hop-by-hop or destination) */
139 static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
141 struct tlvtype_proc *curr;
142 const unsigned char *nh = skb_network_header(skb);
143 int off = skb_network_header_len(skb);
144 int len = (skb_transport_header(skb)[1] + 1) << 3;
146 if (skb_transport_offset(skb) + len > skb_headlen(skb))
147 goto bad;
149 off += 2;
150 len -= 2;
152 while (len > 0) {
153 int optlen = nh[off + 1] + 2;
155 switch (nh[off]) {
156 case IPV6_TLV_PAD0:
157 optlen = 1;
158 break;
160 case IPV6_TLV_PADN:
161 break;
163 default: /* Other TLV code so scan list */
164 if (optlen > len)
165 goto bad;
166 for (curr=procs; curr->type >= 0; curr++) {
167 if (curr->type == nh[off]) {
168 /* type specific length/alignment
169 checks will be performed in the
170 func(). */
171 if (curr->func(skb, off) == 0)
172 return 0;
173 break;
176 if (curr->type < 0) {
177 if (ip6_tlvopt_unknown(skb, off) == 0)
178 return 0;
180 break;
182 off += optlen;
183 len -= optlen;
185 if (len == 0)
186 return 1;
187 bad:
188 kfree_skb(skb);
189 return 0;
192 /*****************************
193 Destination options header.
194 *****************************/
196 #ifdef CONFIG_IPV6_MIP6
197 static int ipv6_dest_hao(struct sk_buff *skb, int optoff)
199 struct ipv6_destopt_hao *hao;
200 struct inet6_skb_parm *opt = IP6CB(skb);
201 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
202 struct in6_addr tmp_addr;
203 int ret;
205 if (opt->dsthao) {
206 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
207 goto discard;
209 opt->dsthao = opt->dst1;
210 opt->dst1 = 0;
212 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
214 if (hao->length != 16) {
215 LIMIT_NETDEBUG(
216 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
217 goto discard;
220 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
221 LIMIT_NETDEBUG(
222 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
223 goto discard;
226 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
227 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
228 if (unlikely(ret < 0))
229 goto discard;
231 if (skb_cloned(skb)) {
232 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
233 goto discard;
235 /* update all variable using below by copied skbuff */
236 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
237 optoff);
238 ipv6h = ipv6_hdr(skb);
241 if (skb->ip_summed == CHECKSUM_COMPLETE)
242 skb->ip_summed = CHECKSUM_NONE;
244 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
245 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
246 ipv6_addr_copy(&hao->addr, &tmp_addr);
248 if (skb->tstamp.tv64 == 0)
249 __net_timestamp(skb);
251 return 1;
253 discard:
254 kfree_skb(skb);
255 return 0;
257 #endif
259 static struct tlvtype_proc tlvprocdestopt_lst[] = {
260 #ifdef CONFIG_IPV6_MIP6
262 .type = IPV6_TLV_HAO,
263 .func = ipv6_dest_hao,
265 #endif
266 {-1, NULL}
269 static int ipv6_destopt_rcv(struct sk_buff *skb)
271 struct inet6_skb_parm *opt = IP6CB(skb);
272 #ifdef CONFIG_IPV6_MIP6
273 __u16 dstbuf;
274 #endif
275 struct dst_entry *dst;
277 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
278 !pskb_may_pull(skb, (skb_transport_offset(skb) +
279 ((skb_transport_header(skb)[1] + 1) << 3)))) {
280 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
281 IPSTATS_MIB_INHDRERRORS);
282 kfree_skb(skb);
283 return -1;
286 opt->lastopt = opt->dst1 = skb_network_header_len(skb);
287 #ifdef CONFIG_IPV6_MIP6
288 dstbuf = opt->dst1;
289 #endif
291 dst = dst_clone(skb->dst);
292 if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
293 dst_release(dst);
294 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
295 opt = IP6CB(skb);
296 #ifdef CONFIG_IPV6_MIP6
297 opt->nhoff = dstbuf;
298 #else
299 opt->nhoff = opt->dst1;
300 #endif
301 return 1;
304 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
305 dst_release(dst);
306 return -1;
309 static struct inet6_protocol destopt_protocol = {
310 .handler = ipv6_destopt_rcv,
311 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
314 void __init ipv6_destopt_init(void)
316 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
317 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
320 /********************************
321 NONE header. No data in packet.
322 ********************************/
324 static int ipv6_nodata_rcv(struct sk_buff *skb)
326 kfree_skb(skb);
327 return 0;
330 static struct inet6_protocol nodata_protocol = {
331 .handler = ipv6_nodata_rcv,
332 .flags = INET6_PROTO_NOPOLICY,
335 void __init ipv6_nodata_init(void)
337 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
338 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
341 /********************************
342 Routing header.
343 ********************************/
345 static int ipv6_rthdr_rcv(struct sk_buff *skb)
347 struct inet6_skb_parm *opt = IP6CB(skb);
348 struct in6_addr *addr = NULL;
349 struct in6_addr daddr;
350 struct inet6_dev *idev;
351 int n, i;
352 struct ipv6_rt_hdr *hdr;
353 struct rt0_hdr *rthdr;
354 int accept_source_route = ipv6_devconf.accept_source_route;
356 if (accept_source_route < 0 ||
357 ((idev = in6_dev_get(skb->dev)) == NULL)) {
358 kfree_skb(skb);
359 return -1;
361 if (idev->cnf.accept_source_route < 0) {
362 in6_dev_put(idev);
363 kfree_skb(skb);
364 return -1;
367 if (accept_source_route > idev->cnf.accept_source_route)
368 accept_source_route = idev->cnf.accept_source_route;
370 in6_dev_put(idev);
372 if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
373 !pskb_may_pull(skb, (skb_transport_offset(skb) +
374 ((skb_transport_header(skb)[1] + 1) << 3)))) {
375 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
376 IPSTATS_MIB_INHDRERRORS);
377 kfree_skb(skb);
378 return -1;
381 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
383 switch (hdr->type) {
384 #ifdef CONFIG_IPV6_MIP6
385 case IPV6_SRCRT_TYPE_2:
386 break;
387 #endif
388 case IPV6_SRCRT_TYPE_0:
389 if (accept_source_route > 0)
390 break;
391 kfree_skb(skb);
392 return -1;
393 default:
394 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
395 IPSTATS_MIB_INHDRERRORS);
396 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
397 (&hdr->type) - skb_network_header(skb));
398 return -1;
401 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
402 skb->pkt_type != PACKET_HOST) {
403 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
404 IPSTATS_MIB_INADDRERRORS);
405 kfree_skb(skb);
406 return -1;
409 looped_back:
410 if (hdr->segments_left == 0) {
411 switch (hdr->type) {
412 #ifdef CONFIG_IPV6_MIP6
413 case IPV6_SRCRT_TYPE_2:
414 /* Silently discard type 2 header unless it was
415 * processed by own
417 if (!addr) {
418 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
419 IPSTATS_MIB_INADDRERRORS);
420 kfree_skb(skb);
421 return -1;
423 break;
424 #endif
425 default:
426 break;
429 opt->lastopt = opt->srcrt = skb_network_header_len(skb);
430 skb->transport_header += (hdr->hdrlen + 1) << 3;
431 opt->dst0 = opt->dst1;
432 opt->dst1 = 0;
433 opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
434 return 1;
437 switch (hdr->type) {
438 case IPV6_SRCRT_TYPE_0:
439 if (hdr->hdrlen & 0x01) {
440 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
441 IPSTATS_MIB_INHDRERRORS);
442 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
443 ((&hdr->hdrlen) -
444 skb_network_header(skb)));
445 return -1;
447 break;
448 #ifdef CONFIG_IPV6_MIP6
449 case IPV6_SRCRT_TYPE_2:
450 /* Silently discard invalid RTH type 2 */
451 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
452 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
453 IPSTATS_MIB_INHDRERRORS);
454 kfree_skb(skb);
455 return -1;
457 break;
458 #endif
462 * This is the routing header forwarding algorithm from
463 * RFC 2460, page 16.
466 n = hdr->hdrlen >> 1;
468 if (hdr->segments_left > n) {
469 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
470 IPSTATS_MIB_INHDRERRORS);
471 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
472 ((&hdr->segments_left) -
473 skb_network_header(skb)));
474 return -1;
477 /* We are about to mangle packet header. Be careful!
478 Do not damage packets queued somewhere.
480 if (skb_cloned(skb)) {
481 /* the copy is a forwarded packet */
482 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
483 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
484 IPSTATS_MIB_OUTDISCARDS);
485 kfree_skb(skb);
486 return -1;
488 hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
491 if (skb->ip_summed == CHECKSUM_COMPLETE)
492 skb->ip_summed = CHECKSUM_NONE;
494 i = n - --hdr->segments_left;
496 rthdr = (struct rt0_hdr *) hdr;
497 addr = rthdr->addr;
498 addr += i - 1;
500 switch (hdr->type) {
501 #ifdef CONFIG_IPV6_MIP6
502 case IPV6_SRCRT_TYPE_2:
503 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
504 (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
505 IPPROTO_ROUTING) < 0) {
506 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
507 IPSTATS_MIB_INADDRERRORS);
508 kfree_skb(skb);
509 return -1;
511 if (!ipv6_chk_home_addr(addr)) {
512 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
513 IPSTATS_MIB_INADDRERRORS);
514 kfree_skb(skb);
515 return -1;
517 break;
518 #endif
519 default:
520 break;
523 if (ipv6_addr_is_multicast(addr)) {
524 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
525 IPSTATS_MIB_INADDRERRORS);
526 kfree_skb(skb);
527 return -1;
530 ipv6_addr_copy(&daddr, addr);
531 ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);
532 ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);
534 dst_release(xchg(&skb->dst, NULL));
535 ip6_route_input(skb);
536 if (skb->dst->error) {
537 skb_push(skb, skb->data - skb_network_header(skb));
538 dst_input(skb);
539 return -1;
542 if (skb->dst->dev->flags&IFF_LOOPBACK) {
543 if (ipv6_hdr(skb)->hop_limit <= 1) {
544 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
545 IPSTATS_MIB_INHDRERRORS);
546 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
547 0, skb->dev);
548 kfree_skb(skb);
549 return -1;
551 ipv6_hdr(skb)->hop_limit--;
552 goto looped_back;
555 skb_push(skb, skb->data - skb_network_header(skb));
556 dst_input(skb);
557 return -1;
560 static struct inet6_protocol rthdr_protocol = {
561 .handler = ipv6_rthdr_rcv,
562 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
565 void __init ipv6_rthdr_init(void)
567 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
568 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
572 This function inverts received rthdr.
573 NOTE: specs allow to make it automatically only if
574 packet authenticated.
576 I will not discuss it here (though, I am really pissed off at
577 this stupid requirement making rthdr idea useless)
579 Actually, it creates severe problems for us.
580 Embryonic requests has no associated sockets,
581 so that user have no control over it and
582 cannot not only to set reply options, but
583 even to know, that someone wants to connect
584 without success. :-(
586 For now we need to test the engine, so that I created
587 temporary (or permanent) backdoor.
588 If listening socket set IPV6_RTHDR to 2, then we invert header.
589 --ANK (980729)
592 struct ipv6_txoptions *
593 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
595 /* Received rthdr:
597 [ H1 -> H2 -> ... H_prev ] daddr=ME
599 Inverted result:
600 [ H_prev -> ... -> H1 ] daddr =sender
602 Note, that IP output engine will rewrite this rthdr
603 by rotating it left by one addr.
606 int n, i;
607 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
608 struct rt0_hdr *irthdr;
609 struct ipv6_txoptions *opt;
610 int hdrlen = ipv6_optlen(hdr);
612 if (hdr->segments_left ||
613 hdr->type != IPV6_SRCRT_TYPE_0 ||
614 hdr->hdrlen & 0x01)
615 return NULL;
617 n = hdr->hdrlen >> 1;
618 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
619 if (opt == NULL)
620 return NULL;
621 memset(opt, 0, sizeof(*opt));
622 opt->tot_len = sizeof(*opt) + hdrlen;
623 opt->srcrt = (void*)(opt+1);
624 opt->opt_nflen = hdrlen;
626 memcpy(opt->srcrt, hdr, sizeof(*hdr));
627 irthdr = (struct rt0_hdr*)opt->srcrt;
628 irthdr->reserved = 0;
629 opt->srcrt->segments_left = n;
630 for (i=0; i<n; i++)
631 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
632 return opt;
635 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
637 /**********************************
638 Hop-by-hop options.
639 **********************************/
642 * Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
644 static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
646 return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);
649 /* Router Alert as of RFC 2711 */
651 static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
653 const unsigned char *nh = skb_network_header(skb);
655 if (nh[optoff + 1] == 2) {
656 IP6CB(skb)->ra = optoff;
657 return 1;
659 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
660 nh[optoff + 1]);
661 kfree_skb(skb);
662 return 0;
665 /* Jumbo payload */
667 static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
669 const unsigned char *nh = skb_network_header(skb);
670 u32 pkt_len;
672 if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
673 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
674 nh[optoff+1]);
675 IP6_INC_STATS_BH(ipv6_skb_idev(skb),
676 IPSTATS_MIB_INHDRERRORS);
677 goto drop;
680 pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
681 if (pkt_len <= IPV6_MAXPLEN) {
682 IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
683 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
684 return 0;
686 if (ipv6_hdr(skb)->payload_len) {
687 IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
688 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
689 return 0;
692 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
693 IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
694 goto drop;
697 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
698 goto drop;
700 return 1;
702 drop:
703 kfree_skb(skb);
704 return 0;
707 static struct tlvtype_proc tlvprochopopt_lst[] = {
709 .type = IPV6_TLV_ROUTERALERT,
710 .func = ipv6_hop_ra,
713 .type = IPV6_TLV_JUMBO,
714 .func = ipv6_hop_jumbo,
716 { -1, }
719 int ipv6_parse_hopopts(struct sk_buff *skb)
721 struct inet6_skb_parm *opt = IP6CB(skb);
724 * skb_network_header(skb) is equal to skb->data, and
725 * skb_network_header_len(skb) is always equal to
726 * sizeof(struct ipv6hdr) by definition of
727 * hop-by-hop options.
729 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
730 !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
731 ((skb_transport_header(skb)[1] + 1) << 3)))) {
732 kfree_skb(skb);
733 return -1;
736 opt->hop = sizeof(struct ipv6hdr);
737 if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
738 skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
739 opt = IP6CB(skb);
740 opt->nhoff = sizeof(struct ipv6hdr);
741 return 1;
743 return -1;
747 * Creating outbound headers.
749 * "build" functions work when skb is filled from head to tail (datagram)
750 * "push" functions work when headers are added from tail to head (tcp)
752 * In both cases we assume, that caller reserved enough room
753 * for headers.
756 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
757 struct ipv6_rt_hdr *opt,
758 struct in6_addr **addr_p)
760 struct rt0_hdr *phdr, *ihdr;
761 int hops;
763 ihdr = (struct rt0_hdr *) opt;
765 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
766 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
768 hops = ihdr->rt_hdr.hdrlen >> 1;
770 if (hops > 1)
771 memcpy(phdr->addr, ihdr->addr + 1,
772 (hops - 1) * sizeof(struct in6_addr));
774 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
775 *addr_p = ihdr->addr;
777 phdr->rt_hdr.nexthdr = *proto;
778 *proto = NEXTHDR_ROUTING;
781 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
783 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
785 memcpy(h, opt, ipv6_optlen(opt));
786 h->nexthdr = *proto;
787 *proto = type;
790 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
791 u8 *proto,
792 struct in6_addr **daddr)
794 if (opt->srcrt) {
795 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
797 * IPV6_RTHDRDSTOPTS is ignored
798 * unless IPV6_RTHDR is set (RFC3542).
800 if (opt->dst0opt)
801 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
803 if (opt->hopopt)
804 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
807 EXPORT_SYMBOL(ipv6_push_nfrag_opts);
809 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
811 if (opt->dst1opt)
812 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
815 struct ipv6_txoptions *
816 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
818 struct ipv6_txoptions *opt2;
820 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
821 if (opt2) {
822 long dif = (char*)opt2 - (char*)opt;
823 memcpy(opt2, opt, opt->tot_len);
824 if (opt2->hopopt)
825 *((char**)&opt2->hopopt) += dif;
826 if (opt2->dst0opt)
827 *((char**)&opt2->dst0opt) += dif;
828 if (opt2->dst1opt)
829 *((char**)&opt2->dst1opt) += dif;
830 if (opt2->srcrt)
831 *((char**)&opt2->srcrt) += dif;
833 return opt2;
836 EXPORT_SYMBOL_GPL(ipv6_dup_options);
838 static int ipv6_renew_option(void *ohdr,
839 struct ipv6_opt_hdr __user *newopt, int newoptlen,
840 int inherit,
841 struct ipv6_opt_hdr **hdr,
842 char **p)
844 if (inherit) {
845 if (ohdr) {
846 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
847 *hdr = (struct ipv6_opt_hdr *)*p;
848 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
850 } else {
851 if (newopt) {
852 if (copy_from_user(*p, newopt, newoptlen))
853 return -EFAULT;
854 *hdr = (struct ipv6_opt_hdr *)*p;
855 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
856 return -EINVAL;
857 *p += CMSG_ALIGN(newoptlen);
860 return 0;
863 struct ipv6_txoptions *
864 ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
865 int newtype,
866 struct ipv6_opt_hdr __user *newopt, int newoptlen)
868 int tot_len = 0;
869 char *p;
870 struct ipv6_txoptions *opt2;
871 int err;
873 if (opt) {
874 if (newtype != IPV6_HOPOPTS && opt->hopopt)
875 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
876 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
877 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
878 if (newtype != IPV6_RTHDR && opt->srcrt)
879 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
880 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
881 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
884 if (newopt && newoptlen)
885 tot_len += CMSG_ALIGN(newoptlen);
887 if (!tot_len)
888 return NULL;
890 tot_len += sizeof(*opt2);
891 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
892 if (!opt2)
893 return ERR_PTR(-ENOBUFS);
895 memset(opt2, 0, tot_len);
897 opt2->tot_len = tot_len;
898 p = (char *)(opt2 + 1);
900 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
901 newtype != IPV6_HOPOPTS,
902 &opt2->hopopt, &p);
903 if (err)
904 goto out;
906 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
907 newtype != IPV6_RTHDRDSTOPTS,
908 &opt2->dst0opt, &p);
909 if (err)
910 goto out;
912 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
913 newtype != IPV6_RTHDR,
914 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
915 if (err)
916 goto out;
918 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
919 newtype != IPV6_DSTOPTS,
920 &opt2->dst1opt, &p);
921 if (err)
922 goto out;
924 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
925 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
926 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
927 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
929 return opt2;
930 out:
931 sock_kfree_s(sk, opt2, opt2->tot_len);
932 return ERR_PTR(err);
935 struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
936 struct ipv6_txoptions *opt)
939 * ignore the dest before srcrt unless srcrt is being included.
940 * --yoshfuji
942 if (opt && opt->dst0opt && !opt->srcrt) {
943 if (opt_space != opt) {
944 memcpy(opt_space, opt, sizeof(*opt_space));
945 opt = opt_space;
947 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
948 opt->dst0opt = NULL;
951 return opt;