2 * Extension Header handling for IPv6
3 * Linux INET6 implementation
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.
19 * yoshfuji : ensure not to overrun while parsing
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>
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>
47 #include <asm/uaccess.h>
50 * Parsing tlv encoded headers.
52 * Parsing function "func" returns 1, if parsing succeed
53 * and 0, if it failed.
54 * It MUST NOT touch skb->h.
59 int (*func)(struct sk_buff *skb, int offset);
62 /*********************
64 *********************/
66 /* An unknown option is detected, decide what to do */
68 static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
70 switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
74 case 1: /* drop packet */
77 case 3: /* Send ICMP if not a multicast address and drop packet */
78 /* Actually, it is redundant check. icmp_send
79 will recheck in any case.
81 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
83 case 2: /* send ICMP PARM PROB regardless and drop packet */
84 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
92 /* Parse tlv encoded option header (hop-by-hop or destination) */
94 static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
96 struct tlvtype_proc *curr;
97 int off = skb->h.raw - skb->nh.raw;
98 int len = ((skb->h.raw[1]+1)<<3);
100 if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
107 int optlen = skb->nh.raw[off+1]+2;
109 switch (skb->nh.raw[off]) {
117 default: /* Other TLV code so scan list */
120 for (curr=procs; curr->type >= 0; curr++) {
121 if (curr->type == skb->nh.raw[off]) {
122 /* type specific length/alignment
123 checks will be performed in the
125 if (curr->func(skb, off) == 0)
130 if (curr->type < 0) {
131 if (ip6_tlvopt_unknown(skb, off) == 0)
146 /*****************************
147 Destination options header.
148 *****************************/
150 static struct tlvtype_proc tlvprocdestopt_lst[] = {
151 /* No destination options are defined now */
155 static int ipv6_destopt_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
157 struct sk_buff *skb = *skbp;
158 struct inet6_skb_parm *opt = IP6CB(skb);
160 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
161 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
162 IP6_INC_STATS_BH(InHdrErrors);
167 opt->dst1 = skb->h.raw - skb->nh.raw;
169 if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
170 skb->h.raw += ((skb->h.raw[1]+1)<<3);
175 IP6_INC_STATS_BH(InHdrErrors);
179 static struct inet6_protocol destopt_protocol = {
180 .handler = ipv6_destopt_rcv,
181 .flags = INET6_PROTO_NOPOLICY,
184 void __init ipv6_destopt_init(void)
186 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
187 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
190 /********************************
191 NONE header. No data in packet.
192 ********************************/
194 static int ipv6_nodata_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
196 struct sk_buff *skb = *skbp;
202 static struct inet6_protocol nodata_protocol = {
203 .handler = ipv6_nodata_rcv,
204 .flags = INET6_PROTO_NOPOLICY,
207 void __init ipv6_nodata_init(void)
209 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
210 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
213 /********************************
215 ********************************/
217 static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp)
219 struct sk_buff *skb = *skbp;
220 struct inet6_skb_parm *opt = IP6CB(skb);
221 struct in6_addr *addr;
222 struct in6_addr daddr;
225 struct ipv6_rt_hdr *hdr;
226 struct rt0_hdr *rthdr;
228 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
229 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
230 IP6_INC_STATS_BH(InHdrErrors);
235 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
237 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
238 skb->pkt_type != PACKET_HOST) {
239 IP6_INC_STATS_BH(InAddrErrors);
245 if (hdr->segments_left == 0) {
246 opt->srcrt = skb->h.raw - skb->nh.raw;
247 skb->h.raw += (hdr->hdrlen + 1) << 3;
248 opt->dst0 = opt->dst1;
250 *nhoffp = (&hdr->nexthdr) - skb->nh.raw;
254 if (hdr->type != IPV6_SRCRT_TYPE_0) {
255 IP6_INC_STATS_BH(InHdrErrors);
256 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
260 if (hdr->hdrlen & 0x01) {
261 IP6_INC_STATS_BH(InHdrErrors);
262 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
267 * This is the routing header forwarding algorithm from
271 n = hdr->hdrlen >> 1;
273 if (hdr->segments_left > n) {
274 IP6_INC_STATS_BH(InHdrErrors);
275 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
279 /* We are about to mangle packet header. Be careful!
280 Do not damage packets queued somewhere.
282 if (skb_cloned(skb)) {
283 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
285 /* the copy is a forwarded packet */
287 IP6_INC_STATS_BH(OutDiscards);
292 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
295 if (skb->ip_summed == CHECKSUM_HW)
296 skb->ip_summed = CHECKSUM_NONE;
298 i = n - --hdr->segments_left;
300 rthdr = (struct rt0_hdr *) hdr;
304 if (ipv6_addr_is_multicast(addr)) {
305 IP6_INC_STATS_BH(InAddrErrors);
310 ipv6_addr_copy(&daddr, addr);
311 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
312 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
314 dst_release(xchg(&skb->dst, NULL));
315 ip6_route_input(skb);
316 if (skb->dst->error) {
320 if (skb->dst->dev->flags&IFF_LOOPBACK) {
321 if (skb->nh.ipv6h->hop_limit <= 1) {
322 IP6_INC_STATS_BH(InHdrErrors);
323 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
328 skb->nh.ipv6h->hop_limit--;
336 static struct inet6_protocol rthdr_protocol = {
337 .handler = ipv6_rthdr_rcv,
338 .flags = INET6_PROTO_NOPOLICY,
341 void __init ipv6_rthdr_init(void)
343 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
344 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
348 This function inverts received rthdr.
349 NOTE: specs allow to make it automatically only if
350 packet authenticated.
352 I will not discuss it here (though, I am really pissed off at
353 this stupid requirement making rthdr idea useless)
355 Actually, it creates severe problems for us.
356 Embryonic requests has no associated sockets,
357 so that user have no control over it and
358 cannot not only to set reply options, but
359 even to know, that someone wants to connect
362 For now we need to test the engine, so that I created
363 temporary (or permanent) backdoor.
364 If listening socket set IPV6_RTHDR to 2, then we invert header.
368 struct ipv6_txoptions *
369 ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
373 [ H1 -> H2 -> ... H_prev ] daddr=ME
376 [ H_prev -> ... -> H1 ] daddr =sender
378 Note, that IP output engine will rewrite this rthdr
379 by rotating it left by one addr.
383 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
384 struct rt0_hdr *irthdr;
385 struct ipv6_txoptions *opt;
386 int hdrlen = ipv6_optlen(hdr);
388 if (hdr->segments_left ||
389 hdr->type != IPV6_SRCRT_TYPE_0 ||
393 n = hdr->hdrlen >> 1;
394 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
397 memset(opt, 0, sizeof(*opt));
398 opt->tot_len = sizeof(*opt) + hdrlen;
399 opt->srcrt = (void*)(opt+1);
400 opt->opt_nflen = hdrlen;
402 memcpy(opt->srcrt, hdr, sizeof(*hdr));
403 irthdr = (struct rt0_hdr*)opt->srcrt;
404 /* Obsolete field, MBZ, when originated by us */
406 opt->srcrt->segments_left = n;
408 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
412 /**********************************
414 **********************************/
416 /* Router Alert as of RFC 2711 */
418 static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
420 if (skb->nh.raw[optoff+1] == 2) {
421 IP6CB(skb)->ra = optoff;
425 printk(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n", skb->nh.raw[optoff+1]));
432 static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
436 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
438 printk(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", skb->nh.raw[optoff+1]));
439 IP6_INC_STATS_BH(InHdrErrors);
443 pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
444 if (pkt_len <= IPV6_MAXPLEN) {
445 IP6_INC_STATS_BH(InHdrErrors);
446 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
449 if (skb->nh.ipv6h->payload_len) {
450 IP6_INC_STATS_BH(InHdrErrors);
451 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
455 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
456 IP6_INC_STATS_BH(InTruncatedPkts);
459 if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
460 __pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
461 if (skb->ip_summed == CHECKSUM_HW)
462 skb->ip_summed = CHECKSUM_NONE;
471 static struct tlvtype_proc tlvprochopopt_lst[] = {
473 .type = IPV6_TLV_ROUTERALERT,
477 .type = IPV6_TLV_JUMBO,
478 .func = ipv6_hop_jumbo,
483 int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
485 IP6CB(skb)->hop = sizeof(struct ipv6hdr);
486 if (ip6_parse_tlv(tlvprochopopt_lst, skb))
487 return sizeof(struct ipv6hdr);
492 * Creating outbound headers.
494 * "build" functions work when skb is filled from head to tail (datagram)
495 * "push" functions work when headers are added from tail to head (tcp)
497 * In both cases we assume, that caller reserved enough room
501 static u8 *ipv6_build_rthdr(struct sk_buff *skb, u8 *prev_hdr,
502 struct ipv6_rt_hdr *opt, struct in6_addr *addr)
504 struct rt0_hdr *phdr, *ihdr;
507 ihdr = (struct rt0_hdr *) opt;
509 phdr = (struct rt0_hdr *) skb_put(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
510 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
512 hops = ihdr->rt_hdr.hdrlen >> 1;
515 memcpy(phdr->addr, ihdr->addr + 1,
516 (hops - 1) * sizeof(struct in6_addr));
518 ipv6_addr_copy(phdr->addr + (hops - 1), addr);
520 phdr->rt_hdr.nexthdr = *prev_hdr;
521 *prev_hdr = NEXTHDR_ROUTING;
522 return &phdr->rt_hdr.nexthdr;
525 static u8 *ipv6_build_exthdr(struct sk_buff *skb, u8 *prev_hdr, u8 type, struct ipv6_opt_hdr *opt)
527 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_put(skb, ipv6_optlen(opt));
529 memcpy(h, opt, ipv6_optlen(opt));
530 h->nexthdr = *prev_hdr;
535 u8 *ipv6_build_nfrag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt,
536 struct in6_addr *daddr, u32 jumbolen)
538 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb->data;
540 if (opt && opt->hopopt)
541 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_HOP, opt->hopopt);
544 u8 *jumboopt = (u8 *)skb_put(skb, 8);
546 if (opt && opt->hopopt) {
547 *jumboopt++ = IPV6_TLV_PADN;
551 h = (struct ipv6_opt_hdr *)jumboopt;
552 h->nexthdr = *prev_hdr;
555 *prev_hdr = NEXTHDR_HOP;
556 prev_hdr = &h->nexthdr;
558 jumboopt[0] = IPV6_TLV_JUMBO;
560 *(u32*)(jumboopt+2) = htonl(jumbolen);
564 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
566 prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
571 u8 *ipv6_build_frag_opts(struct sk_buff *skb, u8 *prev_hdr, struct ipv6_txoptions *opt)
574 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst1opt);
578 static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
579 struct ipv6_rt_hdr *opt,
580 struct in6_addr **addr_p)
582 struct rt0_hdr *phdr, *ihdr;
585 ihdr = (struct rt0_hdr *) opt;
587 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
588 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
590 hops = ihdr->rt_hdr.hdrlen >> 1;
593 memcpy(phdr->addr, ihdr->addr + 1,
594 (hops - 1) * sizeof(struct in6_addr));
596 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
597 *addr_p = ihdr->addr;
599 phdr->rt_hdr.nexthdr = *proto;
600 *proto = NEXTHDR_ROUTING;
603 static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
605 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
607 memcpy(h, opt, ipv6_optlen(opt));
612 void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
614 struct in6_addr **daddr)
617 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
619 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
621 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
624 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
627 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
630 struct ipv6_txoptions *
631 ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
633 struct ipv6_txoptions *opt2;
635 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
637 long dif = (char*)opt2 - (char*)opt;
638 memcpy(opt2, opt, opt->tot_len);
640 *((char**)&opt2->hopopt) += dif;
642 *((char**)&opt2->dst0opt) += dif;
644 *((char**)&opt2->dst1opt) += dif;
646 *((char**)&opt2->srcrt) += dif;