[SK_BUFF]: Introduce ip_hdr(), remove skb->nh.iph
[linux-2.6/verdex.git] / net / ipv6 / exthdrs.c
blob9ebf120ba6d3b83a0a471a38d93646feb621613b
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 - nh;
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 **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_network_header(skb)[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 const unsigned char *nh = skb_network_header(skb);
146 int off = skb->h.raw - skb->nh.raw;
147 int len = ((skb->h.raw[1]+1)<<3);
149 if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
150 goto bad;
152 off += 2;
153 len -= 2;
155 while (len > 0) {
156 int optlen = nh[off + 1] + 2;
158 switch (nh[off]) {
159 case IPV6_TLV_PAD0:
160 optlen = 1;
161 break;
163 case IPV6_TLV_PADN:
164 break;
166 default: /* Other TLV code so scan list */
167 if (optlen > len)
168 goto bad;
169 for (curr=procs; curr->type >= 0; curr++) {
170 if (curr->type == nh[off]) {
171 /* type specific length/alignment
172 checks will be performed in the
173 func(). */
174 if (curr->func(skbp, off) == 0)
175 return 0;
176 break;
179 if (curr->type < 0) {
180 if (ip6_tlvopt_unknown(skbp, off) == 0)
181 return 0;
183 break;
185 off += optlen;
186 len -= optlen;
188 if (len == 0)
189 return 1;
190 bad:
191 kfree_skb(skb);
192 return 0;
195 /*****************************
196 Destination options header.
197 *****************************/
199 #ifdef CONFIG_IPV6_MIP6
200 static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
202 struct sk_buff *skb = *skbp;
203 struct ipv6_destopt_hao *hao;
204 struct inet6_skb_parm *opt = IP6CB(skb);
205 struct ipv6hdr *ipv6h = skb->nh.ipv6h;
206 struct in6_addr tmp_addr;
207 int ret;
209 if (opt->dsthao) {
210 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
211 goto discard;
213 opt->dsthao = opt->dst1;
214 opt->dst1 = 0;
216 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
218 if (hao->length != 16) {
219 LIMIT_NETDEBUG(
220 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
221 goto discard;
224 if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
225 LIMIT_NETDEBUG(
226 KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr));
227 goto discard;
230 ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
231 (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
232 if (unlikely(ret < 0))
233 goto discard;
235 if (skb_cloned(skb)) {
236 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
237 struct inet6_skb_parm *opt2;
239 if (skb2 == NULL)
240 goto discard;
242 opt2 = IP6CB(skb2);
243 memcpy(opt2, opt, sizeof(*opt2));
245 kfree_skb(skb);
247 /* update all variable using below by copied skbuff */
248 *skbp = skb = skb2;
249 hao = (struct ipv6_destopt_hao *)(skb_network_header(skb2) +
250 optoff);
251 ipv6h = skb2->nh.ipv6h;
254 if (skb->ip_summed == CHECKSUM_COMPLETE)
255 skb->ip_summed = CHECKSUM_NONE;
257 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
258 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
259 ipv6_addr_copy(&hao->addr, &tmp_addr);
261 if (skb->tstamp.tv64 == 0)
262 __net_timestamp(skb);
264 return 1;
266 discard:
267 kfree_skb(skb);
268 return 0;
270 #endif
272 static struct tlvtype_proc tlvprocdestopt_lst[] = {
273 #ifdef CONFIG_IPV6_MIP6
275 .type = IPV6_TLV_HAO,
276 .func = ipv6_dest_hao,
278 #endif
279 {-1, NULL}
282 static int ipv6_destopt_rcv(struct sk_buff **skbp)
284 struct sk_buff *skb = *skbp;
285 struct inet6_skb_parm *opt = IP6CB(skb);
286 #ifdef CONFIG_IPV6_MIP6
287 __u16 dstbuf;
288 #endif
289 struct dst_entry *dst;
291 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
292 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
293 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
294 IPSTATS_MIB_INHDRERRORS);
295 kfree_skb(skb);
296 return -1;
299 opt->lastopt = skb->h.raw - skb->nh.raw;
300 opt->dst1 = skb->h.raw - skb->nh.raw;
301 #ifdef CONFIG_IPV6_MIP6
302 dstbuf = opt->dst1;
303 #endif
305 dst = dst_clone(skb->dst);
306 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
307 dst_release(dst);
308 skb = *skbp;
309 skb->h.raw += ((skb->h.raw[1]+1)<<3);
310 opt = IP6CB(skb);
311 #ifdef CONFIG_IPV6_MIP6
312 opt->nhoff = dstbuf;
313 #else
314 opt->nhoff = opt->dst1;
315 #endif
316 return 1;
319 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
320 dst_release(dst);
321 return -1;
324 static struct inet6_protocol destopt_protocol = {
325 .handler = ipv6_destopt_rcv,
326 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
329 void __init ipv6_destopt_init(void)
331 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
332 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
335 /********************************
336 NONE header. No data in packet.
337 ********************************/
339 static int ipv6_nodata_rcv(struct sk_buff **skbp)
341 struct sk_buff *skb = *skbp;
343 kfree_skb(skb);
344 return 0;
347 static struct inet6_protocol nodata_protocol = {
348 .handler = ipv6_nodata_rcv,
349 .flags = INET6_PROTO_NOPOLICY,
352 void __init ipv6_nodata_init(void)
354 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
355 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
358 /********************************
359 Routing header.
360 ********************************/
362 static int ipv6_rthdr_rcv(struct sk_buff **skbp)
364 struct sk_buff *skb = *skbp;
365 struct inet6_skb_parm *opt = IP6CB(skb);
366 struct in6_addr *addr = NULL;
367 struct in6_addr daddr;
368 struct inet6_dev *idev;
369 int n, i;
370 struct ipv6_rt_hdr *hdr;
371 struct rt0_hdr *rthdr;
372 int accept_source_route = ipv6_devconf.accept_source_route;
374 if (accept_source_route < 0 ||
375 ((idev = in6_dev_get(skb->dev)) == NULL)) {
376 kfree_skb(skb);
377 return -1;
379 if (idev->cnf.accept_source_route < 0) {
380 in6_dev_put(idev);
381 kfree_skb(skb);
382 return -1;
385 if (accept_source_route > idev->cnf.accept_source_route)
386 accept_source_route = idev->cnf.accept_source_route;
388 in6_dev_put(idev);
390 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
391 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
392 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
393 IPSTATS_MIB_INHDRERRORS);
394 kfree_skb(skb);
395 return -1;
398 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
400 switch (hdr->type) {
401 #ifdef CONFIG_IPV6_MIP6
402 break;
403 #endif
404 case IPV6_SRCRT_TYPE_0:
405 if (accept_source_route > 0)
406 break;
407 kfree_skb(skb);
408 return -1;
409 default:
410 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
411 IPSTATS_MIB_INHDRERRORS);
412 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
413 (&hdr->type) - skb_network_header(skb));
414 return -1;
417 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
418 skb->pkt_type != PACKET_HOST) {
419 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
420 IPSTATS_MIB_INADDRERRORS);
421 kfree_skb(skb);
422 return -1;
425 looped_back:
426 if (hdr->segments_left == 0) {
427 switch (hdr->type) {
428 #ifdef CONFIG_IPV6_MIP6
429 case IPV6_SRCRT_TYPE_2:
430 /* Silently discard type 2 header unless it was
431 * processed by own
433 if (!addr) {
434 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
435 IPSTATS_MIB_INADDRERRORS);
436 kfree_skb(skb);
437 return -1;
439 break;
440 #endif
441 default:
442 break;
445 opt->lastopt = skb->h.raw - skb->nh.raw;
446 opt->srcrt = skb->h.raw - skb->nh.raw;
447 skb->h.raw += (hdr->hdrlen + 1) << 3;
448 opt->dst0 = opt->dst1;
449 opt->dst1 = 0;
450 opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
451 return 1;
454 switch (hdr->type) {
455 case IPV6_SRCRT_TYPE_0:
456 if (hdr->hdrlen & 0x01) {
457 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
458 IPSTATS_MIB_INHDRERRORS);
459 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
460 ((&hdr->hdrlen) -
461 skb_network_header(skb)));
462 return -1;
464 break;
465 #ifdef CONFIG_IPV6_MIP6
466 case IPV6_SRCRT_TYPE_2:
467 /* Silently discard invalid RTH type 2 */
468 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
469 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
470 IPSTATS_MIB_INHDRERRORS);
471 kfree_skb(skb);
472 return -1;
474 break;
475 #endif
479 * This is the routing header forwarding algorithm from
480 * RFC 2460, page 16.
483 n = hdr->hdrlen >> 1;
485 if (hdr->segments_left > n) {
486 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
487 IPSTATS_MIB_INHDRERRORS);
488 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
489 ((&hdr->segments_left) -
490 skb_network_header(skb)));
491 return -1;
494 /* We are about to mangle packet header. Be careful!
495 Do not damage packets queued somewhere.
497 if (skb_cloned(skb)) {
498 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
499 /* the copy is a forwarded packet */
500 if (skb2 == NULL) {
501 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
502 IPSTATS_MIB_OUTDISCARDS);
503 kfree_skb(skb);
504 return -1;
506 kfree_skb(skb);
507 *skbp = skb = skb2;
508 opt = IP6CB(skb2);
509 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
512 if (skb->ip_summed == CHECKSUM_COMPLETE)
513 skb->ip_summed = CHECKSUM_NONE;
515 i = n - --hdr->segments_left;
517 rthdr = (struct rt0_hdr *) hdr;
518 addr = rthdr->addr;
519 addr += i - 1;
521 switch (hdr->type) {
522 #ifdef CONFIG_IPV6_MIP6
523 case IPV6_SRCRT_TYPE_2:
524 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
525 (xfrm_address_t *)&skb->nh.ipv6h->saddr,
526 IPPROTO_ROUTING) < 0) {
527 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
528 IPSTATS_MIB_INADDRERRORS);
529 kfree_skb(skb);
530 return -1;
532 if (!ipv6_chk_home_addr(addr)) {
533 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
534 IPSTATS_MIB_INADDRERRORS);
535 kfree_skb(skb);
536 return -1;
538 break;
539 #endif
540 default:
541 break;
544 if (ipv6_addr_is_multicast(addr)) {
545 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
546 IPSTATS_MIB_INADDRERRORS);
547 kfree_skb(skb);
548 return -1;
551 ipv6_addr_copy(&daddr, addr);
552 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
553 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
555 dst_release(xchg(&skb->dst, NULL));
556 ip6_route_input(skb);
557 if (skb->dst->error) {
558 skb_push(skb, skb->data - skb_network_header(skb));
559 dst_input(skb);
560 return -1;
563 if (skb->dst->dev->flags&IFF_LOOPBACK) {
564 if (skb->nh.ipv6h->hop_limit <= 1) {
565 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
566 IPSTATS_MIB_INHDRERRORS);
567 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
568 0, skb->dev);
569 kfree_skb(skb);
570 return -1;
572 skb->nh.ipv6h->hop_limit--;
573 goto looped_back;
576 skb_push(skb, skb->data - skb_network_header(skb));
577 dst_input(skb);
578 return -1;
581 static struct inet6_protocol rthdr_protocol = {
582 .handler = ipv6_rthdr_rcv,
583 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
586 void __init ipv6_rthdr_init(void)
588 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
589 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
593 This function inverts received rthdr.
594 NOTE: specs allow to make it automatically only if
595 packet authenticated.
597 I will not discuss it here (though, I am really pissed off at
598 this stupid requirement making rthdr idea useless)
600 Actually, it creates severe problems for us.
601 Embryonic requests has no associated sockets,
602 so that user have no control over it and
603 cannot not only to set reply options, but
604 even to know, that someone wants to connect
605 without success. :-(
607 For now we need to test the engine, so that I created
608 temporary (or permanent) backdoor.
609 If listening socket set IPV6_RTHDR to 2, then we invert header.
610 --ANK (980729)
613 struct ipv6_txoptions *
614 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
616 /* Received rthdr:
618 [ H1 -> H2 -> ... H_prev ] daddr=ME
620 Inverted result:
621 [ H_prev -> ... -> H1 ] daddr =sender
623 Note, that IP output engine will rewrite this rthdr
624 by rotating it left by one addr.
627 int n, i;
628 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
629 struct rt0_hdr *irthdr;
630 struct ipv6_txoptions *opt;
631 int hdrlen = ipv6_optlen(hdr);
633 if (hdr->segments_left ||
634 hdr->type != IPV6_SRCRT_TYPE_0 ||
635 hdr->hdrlen & 0x01)
636 return NULL;
638 n = hdr->hdrlen >> 1;
639 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
640 if (opt == NULL)
641 return NULL;
642 memset(opt, 0, sizeof(*opt));
643 opt->tot_len = sizeof(*opt) + hdrlen;
644 opt->srcrt = (void*)(opt+1);
645 opt->opt_nflen = hdrlen;
647 memcpy(opt->srcrt, hdr, sizeof(*hdr));
648 irthdr = (struct rt0_hdr*)opt->srcrt;
649 irthdr->reserved = 0;
650 opt->srcrt->segments_left = n;
651 for (i=0; i<n; i++)
652 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
653 return opt;
656 EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
658 /**********************************
659 Hop-by-hop options.
660 **********************************/
662 /* Router Alert as of RFC 2711 */
664 static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
666 struct sk_buff *skb = *skbp;
667 const unsigned char *nh = skb_network_header(skb);
669 if (nh[optoff + 1] == 2) {
670 IP6CB(skb)->ra = optoff;
671 return 1;
673 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
674 nh[optoff + 1]);
675 kfree_skb(skb);
676 return 0;
679 /* Jumbo payload */
681 static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
683 struct sk_buff *skb = *skbp;
684 const unsigned char *nh = skb_network_header(skb);
685 u32 pkt_len;
687 if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
688 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
689 nh[optoff+1]);
690 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
691 IPSTATS_MIB_INHDRERRORS);
692 goto drop;
695 pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
696 if (pkt_len <= IPV6_MAXPLEN) {
697 IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), 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(ip6_dst_idev(skb->dst), 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(ip6_dst_idev(skb->dst), 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_network_header(skb) 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 EXPORT_SYMBOL(ipv6_push_nfrag_opts);
825 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
827 if (opt->dst1opt)
828 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
831 struct ipv6_txoptions *
832 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
834 struct ipv6_txoptions *opt2;
836 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
837 if (opt2) {
838 long dif = (char*)opt2 - (char*)opt;
839 memcpy(opt2, opt, opt->tot_len);
840 if (opt2->hopopt)
841 *((char**)&opt2->hopopt) += dif;
842 if (opt2->dst0opt)
843 *((char**)&opt2->dst0opt) += dif;
844 if (opt2->dst1opt)
845 *((char**)&opt2->dst1opt) += dif;
846 if (opt2->srcrt)
847 *((char**)&opt2->srcrt) += dif;
849 return opt2;
852 EXPORT_SYMBOL_GPL(ipv6_dup_options);
854 static int ipv6_renew_option(void *ohdr,
855 struct ipv6_opt_hdr __user *newopt, int newoptlen,
856 int inherit,
857 struct ipv6_opt_hdr **hdr,
858 char **p)
860 if (inherit) {
861 if (ohdr) {
862 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
863 *hdr = (struct ipv6_opt_hdr *)*p;
864 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
866 } else {
867 if (newopt) {
868 if (copy_from_user(*p, newopt, newoptlen))
869 return -EFAULT;
870 *hdr = (struct ipv6_opt_hdr *)*p;
871 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
872 return -EINVAL;
873 *p += CMSG_ALIGN(newoptlen);
876 return 0;
879 struct ipv6_txoptions *
880 ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
881 int newtype,
882 struct ipv6_opt_hdr __user *newopt, int newoptlen)
884 int tot_len = 0;
885 char *p;
886 struct ipv6_txoptions *opt2;
887 int err;
889 if (opt) {
890 if (newtype != IPV6_HOPOPTS && opt->hopopt)
891 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
892 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
893 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
894 if (newtype != IPV6_RTHDR && opt->srcrt)
895 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
896 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
897 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
900 if (newopt && newoptlen)
901 tot_len += CMSG_ALIGN(newoptlen);
903 if (!tot_len)
904 return NULL;
906 tot_len += sizeof(*opt2);
907 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
908 if (!opt2)
909 return ERR_PTR(-ENOBUFS);
911 memset(opt2, 0, tot_len);
913 opt2->tot_len = tot_len;
914 p = (char *)(opt2 + 1);
916 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
917 newtype != IPV6_HOPOPTS,
918 &opt2->hopopt, &p);
919 if (err)
920 goto out;
922 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
923 newtype != IPV6_RTHDRDSTOPTS,
924 &opt2->dst0opt, &p);
925 if (err)
926 goto out;
928 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
929 newtype != IPV6_RTHDR,
930 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
931 if (err)
932 goto out;
934 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
935 newtype != IPV6_DSTOPTS,
936 &opt2->dst1opt, &p);
937 if (err)
938 goto out;
940 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
941 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
942 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
943 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
945 return opt2;
946 out:
947 sock_kfree_s(sk, opt2, opt2->tot_len);
948 return ERR_PTR(err);
951 struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
952 struct ipv6_txoptions *opt)
955 * ignore the dest before srcrt unless srcrt is being included.
956 * --yoshfuji
958 if (opt && opt->dst0opt && !opt->srcrt) {
959 if (opt_space != opt) {
960 memcpy(opt_space, opt, sizeof(*opt_space));
961 opt = opt_space;
963 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
964 opt->dst0opt = NULL;
967 return opt;