blob: 6a6466bb5f26ef90b8aac0bf57f1224679595dce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Extension Header handling for IPv6
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Andi Kleen <ak@muc.de>
8 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
9 *
10 * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $
11 *
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.
16 */
17
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{}.
24 */
25
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>
35
36#include <net/sock.h>
37#include <net/snmp.h>
38
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>
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -070046#ifdef CONFIG_IPV6_MIP6
47#include <net/xfrm.h>
48#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#include <asm/uaccess.h>
51
Masahide NAKAMURAc61a40432006-08-23 19:18:35 -070052int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
53{
54 int packet_len = skb->tail - skb->nh.raw;
55 struct ipv6_opt_hdr *hdr;
56 int len;
57
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);
62
63 if (offset + len > packet_len)
64 goto bad;
65
66 offset += 2;
67 len -= 2;
68
69 while (len > 0) {
70 int opttype = skb->nh.raw[offset];
71 int optlen;
72
73 if (opttype == type)
74 return offset;
75
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;
85 }
86 offset += optlen;
87 len -= optlen;
88 }
89 /* not_found */
90 return -1;
91 bad:
92 return -1;
93}
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095/*
96 * Parsing tlv encoded headers.
97 *
98 * Parsing function "func" returns 1, if parsing succeed
99 * and 0, if it failed.
100 * It MUST NOT touch skb->h.
101 */
102
103struct tlvtype_proc {
104 int type;
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700105 int (*func)(struct sk_buff **skbp, int offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106};
107
108/*********************
109 Generic functions
110 *********************/
111
112/* An unknown option is detected, decide what to do */
113
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700114static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700116 struct sk_buff *skb = *skbp;
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
119 case 0: /* ignore */
120 return 1;
121
122 case 1: /* drop packet */
123 break;
124
125 case 3: /* Send ICMP if not a multicast address and drop packet */
126 /* Actually, it is redundant check. icmp_send
127 will recheck in any case.
128 */
129 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
130 break;
131 case 2: /* send ICMP PARM PROB regardless and drop packet */
132 icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
133 return 0;
134 };
135
136 kfree_skb(skb);
137 return 0;
138}
139
140/* Parse tlv encoded option header (hop-by-hop or destination) */
141
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700142static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700144 struct sk_buff *skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 struct tlvtype_proc *curr;
146 int off = skb->h.raw - skb->nh.raw;
147 int len = ((skb->h.raw[1]+1)<<3);
148
149 if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
150 goto bad;
151
152 off += 2;
153 len -= 2;
154
155 while (len > 0) {
156 int optlen = skb->nh.raw[off+1]+2;
157
158 switch (skb->nh.raw[off]) {
159 case IPV6_TLV_PAD0:
160 optlen = 1;
161 break;
162
163 case IPV6_TLV_PADN:
164 break;
165
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 == skb->nh.raw[off]) {
171 /* type specific length/alignment
172 checks will be performed in the
173 func(). */
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700174 if (curr->func(skbp, off) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 return 0;
176 break;
177 }
178 }
179 if (curr->type < 0) {
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700180 if (ip6_tlvopt_unknown(skbp, off) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return 0;
182 }
183 break;
184 }
185 off += optlen;
186 len -= optlen;
187 }
188 if (len == 0)
189 return 1;
190bad:
191 kfree_skb(skb);
192 return 0;
193}
194
195/*****************************
196 Destination options header.
197 *****************************/
198
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700199#ifdef CONFIG_IPV6_MIP6
200static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
201{
202 struct sk_buff *skb = *skbp;
203 struct ipv6_destopt_hao *hao;
204 struct inet6_skb_parm *opt = IP6CB(skb);
205 struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw;
206 struct in6_addr tmp_addr;
207 int ret;
208
209 if (opt->dsthao) {
210 LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
211 goto discard;
212 }
213 opt->dsthao = opt->dst1;
214 opt->dst1 = 0;
215
216 hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
217
218 if (hao->length != 16) {
219 LIMIT_NETDEBUG(
220 KERN_DEBUG "hao invalid option length = %d\n", hao->length);
221 goto discard;
222 }
223
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;
228 }
229
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;
234
235 if (skb_cloned(skb)) {
236 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
237 if (skb2 == NULL)
238 goto discard;
239
240 kfree_skb(skb);
241
242 /* update all variable using below by copied skbuff */
243 *skbp = skb = skb2;
244 hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff);
245 ipv6h = (struct ipv6hdr *)skb2->nh.raw;
246 }
247
248 if (skb->ip_summed == CHECKSUM_COMPLETE)
249 skb->ip_summed = CHECKSUM_NONE;
250
251 ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
252 ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
253 ipv6_addr_copy(&hao->addr, &tmp_addr);
254
255 if (skb->tstamp.off_sec == 0)
256 __net_timestamp(skb);
257
258 return 1;
259
260 discard:
261 kfree_skb(skb);
262 return 0;
263}
264#endif
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static struct tlvtype_proc tlvprocdestopt_lst[] = {
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700267#ifdef CONFIG_IPV6_MIP6
268 {
269 .type = IPV6_TLV_HAO,
270 .func = ipv6_dest_hao,
271 },
272#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 {-1, NULL}
274};
275
Patrick McHardy951dbc82006-01-06 23:02:34 -0800276static int ipv6_destopt_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct sk_buff *skb = *skbp;
279 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700280#ifdef CONFIG_IPV6_MIP6
281 __u16 dstbuf;
282#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
285 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
286 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
287 kfree_skb(skb);
288 return -1;
289 }
290
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900291 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 opt->dst1 = skb->h.raw - skb->nh.raw;
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700293#ifdef CONFIG_IPV6_MIP6
294 dstbuf = opt->dst1;
295#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700297 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
298 skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 skb->h.raw += ((skb->h.raw[1]+1)<<3);
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700300#ifdef CONFIG_IPV6_MIP6
301 opt->nhoff = dstbuf;
302#else
Patrick McHardy951dbc82006-01-06 23:02:34 -0800303 opt->nhoff = opt->dst1;
Masahide NAKAMURAa831f5b2006-08-23 19:24:48 -0700304#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return 1;
306 }
307
308 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
309 return -1;
310}
311
312static struct inet6_protocol destopt_protocol = {
313 .handler = ipv6_destopt_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700314 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315};
316
317void __init ipv6_destopt_init(void)
318{
319 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
320 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
321}
322
323/********************************
324 NONE header. No data in packet.
325 ********************************/
326
Patrick McHardy951dbc82006-01-06 23:02:34 -0800327static int ipv6_nodata_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 struct sk_buff *skb = *skbp;
330
331 kfree_skb(skb);
332 return 0;
333}
334
335static struct inet6_protocol nodata_protocol = {
336 .handler = ipv6_nodata_rcv,
337 .flags = INET6_PROTO_NOPOLICY,
338};
339
340void __init ipv6_nodata_init(void)
341{
342 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
343 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
344}
345
346/********************************
347 Routing header.
348 ********************************/
349
Patrick McHardy951dbc82006-01-06 23:02:34 -0800350static int ipv6_rthdr_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
352 struct sk_buff *skb = *skbp;
353 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700354 struct in6_addr *addr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 struct in6_addr daddr;
356 int n, i;
357
358 struct ipv6_rt_hdr *hdr;
359 struct rt0_hdr *rthdr;
360
361 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
362 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
363 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
364 kfree_skb(skb);
365 return -1;
366 }
367
368 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
369
370 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
371 skb->pkt_type != PACKET_HOST) {
372 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
373 kfree_skb(skb);
374 return -1;
375 }
376
377looped_back:
378 if (hdr->segments_left == 0) {
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700379 switch (hdr->type) {
380#ifdef CONFIG_IPV6_MIP6
381 case IPV6_SRCRT_TYPE_2:
382 /* Silently discard type 2 header unless it was
383 * processed by own
384 */
385 if (!addr) {
386 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
387 kfree_skb(skb);
388 return -1;
389 }
390 break;
391#endif
392 default:
393 break;
394 }
395
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900396 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 opt->srcrt = skb->h.raw - skb->nh.raw;
398 skb->h.raw += (hdr->hdrlen + 1) << 3;
399 opt->dst0 = opt->dst1;
400 opt->dst1 = 0;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800401 opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return 1;
403 }
404
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700405 switch (hdr->type) {
406 case IPV6_SRCRT_TYPE_0:
407 if (hdr->hdrlen & 0x01) {
408 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
409 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
410 return -1;
411 }
412 break;
413#ifdef CONFIG_IPV6_MIP6
414 case IPV6_SRCRT_TYPE_2:
415 /* Silently discard invalid RTH type 2 */
416 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
417 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
418 kfree_skb(skb);
419 return -1;
420 }
421 break;
422#endif
423 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
425 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
426 return -1;
427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 /*
430 * This is the routing header forwarding algorithm from
431 * RFC 2460, page 16.
432 */
433
434 n = hdr->hdrlen >> 1;
435
436 if (hdr->segments_left > n) {
437 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
438 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
439 return -1;
440 }
441
442 /* We are about to mangle packet header. Be careful!
443 Do not damage packets queued somewhere.
444 */
445 if (skb_cloned(skb)) {
446 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
447 kfree_skb(skb);
448 /* the copy is a forwarded packet */
449 if (skb2 == NULL) {
450 IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS);
451 return -1;
452 }
453 *skbp = skb = skb2;
454 opt = IP6CB(skb2);
455 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
456 }
457
Patrick McHardy84fa7932006-08-29 16:44:56 -0700458 if (skb->ip_summed == CHECKSUM_COMPLETE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 skb->ip_summed = CHECKSUM_NONE;
460
461 i = n - --hdr->segments_left;
462
463 rthdr = (struct rt0_hdr *) hdr;
464 addr = rthdr->addr;
465 addr += i - 1;
466
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700467 switch (hdr->type) {
468#ifdef CONFIG_IPV6_MIP6
469 case IPV6_SRCRT_TYPE_2:
470 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
471 (xfrm_address_t *)&skb->nh.ipv6h->saddr,
472 IPPROTO_ROUTING) < 0) {
473 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
474 kfree_skb(skb);
475 return -1;
476 }
477 if (!ipv6_chk_home_addr(addr)) {
478 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
479 kfree_skb(skb);
480 return -1;
481 }
482 break;
483#endif
484 default:
485 break;
486 }
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 if (ipv6_addr_is_multicast(addr)) {
489 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
490 kfree_skb(skb);
491 return -1;
492 }
493
494 ipv6_addr_copy(&daddr, addr);
495 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
496 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
497
498 dst_release(xchg(&skb->dst, NULL));
499 ip6_route_input(skb);
500 if (skb->dst->error) {
501 skb_push(skb, skb->data - skb->nh.raw);
502 dst_input(skb);
503 return -1;
504 }
505
506 if (skb->dst->dev->flags&IFF_LOOPBACK) {
507 if (skb->nh.ipv6h->hop_limit <= 1) {
508 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
509 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
510 0, skb->dev);
511 kfree_skb(skb);
512 return -1;
513 }
514 skb->nh.ipv6h->hop_limit--;
515 goto looped_back;
516 }
517
518 skb_push(skb, skb->data - skb->nh.raw);
519 dst_input(skb);
520 return -1;
521}
522
523static struct inet6_protocol rthdr_protocol = {
524 .handler = ipv6_rthdr_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700525 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526};
527
528void __init ipv6_rthdr_init(void)
529{
530 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
531 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
532};
533
534/*
535 This function inverts received rthdr.
536 NOTE: specs allow to make it automatically only if
537 packet authenticated.
538
539 I will not discuss it here (though, I am really pissed off at
540 this stupid requirement making rthdr idea useless)
541
542 Actually, it creates severe problems for us.
543 Embryonic requests has no associated sockets,
544 so that user have no control over it and
545 cannot not only to set reply options, but
546 even to know, that someone wants to connect
547 without success. :-(
548
549 For now we need to test the engine, so that I created
550 temporary (or permanent) backdoor.
551 If listening socket set IPV6_RTHDR to 2, then we invert header.
552 --ANK (980729)
553 */
554
555struct ipv6_txoptions *
556ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
557{
558 /* Received rthdr:
559
560 [ H1 -> H2 -> ... H_prev ] daddr=ME
561
562 Inverted result:
563 [ H_prev -> ... -> H1 ] daddr =sender
564
565 Note, that IP output engine will rewrite this rthdr
566 by rotating it left by one addr.
567 */
568
569 int n, i;
570 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
571 struct rt0_hdr *irthdr;
572 struct ipv6_txoptions *opt;
573 int hdrlen = ipv6_optlen(hdr);
574
575 if (hdr->segments_left ||
576 hdr->type != IPV6_SRCRT_TYPE_0 ||
577 hdr->hdrlen & 0x01)
578 return NULL;
579
580 n = hdr->hdrlen >> 1;
581 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
582 if (opt == NULL)
583 return NULL;
584 memset(opt, 0, sizeof(*opt));
585 opt->tot_len = sizeof(*opt) + hdrlen;
586 opt->srcrt = (void*)(opt+1);
587 opt->opt_nflen = hdrlen;
588
589 memcpy(opt->srcrt, hdr, sizeof(*hdr));
590 irthdr = (struct rt0_hdr*)opt->srcrt;
Brian Haleye6df4392005-09-10 00:15:06 -0700591 irthdr->reserved = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 opt->srcrt->segments_left = n;
593 for (i=0; i<n; i++)
594 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
595 return opt;
596}
597
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800598EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600/**********************************
601 Hop-by-hop options.
602 **********************************/
603
604/* Router Alert as of RFC 2711 */
605
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700606static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700608 struct sk_buff *skb = *skbp;
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (skb->nh.raw[optoff+1] == 2) {
611 IP6CB(skb)->ra = optoff;
612 return 1;
613 }
Patrick McHardy64ce2072005-08-09 20:50:53 -0700614 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
615 skb->nh.raw[optoff+1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 kfree_skb(skb);
617 return 0;
618}
619
620/* Jumbo payload */
621
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700622static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700624 struct sk_buff *skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 u32 pkt_len;
626
627 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700628 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
629 skb->nh.raw[optoff+1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
631 goto drop;
632 }
633
634 pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
635 if (pkt_len <= IPV6_MAXPLEN) {
636 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
637 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
638 return 0;
639 }
640 if (skb->nh.ipv6h->payload_len) {
641 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
642 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
643 return 0;
644 }
645
646 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
647 IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
648 goto drop;
649 }
Stephen Hemminger42ca89c2005-09-08 12:57:43 -0700650
651 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
652 goto drop;
653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return 1;
655
656drop:
657 kfree_skb(skb);
658 return 0;
659}
660
661static struct tlvtype_proc tlvprochopopt_lst[] = {
662 {
663 .type = IPV6_TLV_ROUTERALERT,
664 .func = ipv6_hop_ra,
665 },
666 {
667 .type = IPV6_TLV_JUMBO,
668 .func = ipv6_hop_jumbo,
669 },
670 { -1, }
671};
672
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700673int ipv6_parse_hopopts(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700675 struct sk_buff *skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800676 struct inet6_skb_parm *opt = IP6CB(skb);
677
YOSHIFUJI Hideakiec670092006-04-18 14:46:26 -0700678 /*
679 * skb->nh.raw is equal to skb->data, and
680 * skb->h.raw - skb->nh.raw is always equal to
681 * sizeof(struct ipv6hdr) by definition of
682 * hop-by-hop options.
683 */
684 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
685 !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
686 kfree_skb(skb);
687 return -1;
688 }
689
Patrick McHardy951dbc82006-01-06 23:02:34 -0800690 opt->hop = sizeof(struct ipv6hdr);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700691 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
692 skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800693 skb->h.raw += (skb->h.raw[1]+1)<<3;
694 opt->nhoff = sizeof(struct ipv6hdr);
YOSHIFUJI Hideakib8097392006-04-18 14:48:45 -0700695 return 1;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return -1;
698}
699
700/*
701 * Creating outbound headers.
702 *
703 * "build" functions work when skb is filled from head to tail (datagram)
704 * "push" functions work when headers are added from tail to head (tcp)
705 *
706 * In both cases we assume, that caller reserved enough room
707 * for headers.
708 */
709
710static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
711 struct ipv6_rt_hdr *opt,
712 struct in6_addr **addr_p)
713{
714 struct rt0_hdr *phdr, *ihdr;
715 int hops;
716
717 ihdr = (struct rt0_hdr *) opt;
718
719 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
720 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
721
722 hops = ihdr->rt_hdr.hdrlen >> 1;
723
724 if (hops > 1)
725 memcpy(phdr->addr, ihdr->addr + 1,
726 (hops - 1) * sizeof(struct in6_addr));
727
728 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
729 *addr_p = ihdr->addr;
730
731 phdr->rt_hdr.nexthdr = *proto;
732 *proto = NEXTHDR_ROUTING;
733}
734
735static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
736{
737 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
738
739 memcpy(h, opt, ipv6_optlen(opt));
740 h->nexthdr = *proto;
741 *proto = type;
742}
743
744void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
745 u8 *proto,
746 struct in6_addr **daddr)
747{
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900748 if (opt->srcrt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900750 /*
751 * IPV6_RTHDRDSTOPTS is ignored
752 * unless IPV6_RTHDR is set (RFC3542).
753 */
754 if (opt->dst0opt)
755 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 if (opt->hopopt)
758 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
759}
760
761void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
762{
763 if (opt->dst1opt)
764 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
765}
766
767struct ipv6_txoptions *
768ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
769{
770 struct ipv6_txoptions *opt2;
771
772 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
773 if (opt2) {
774 long dif = (char*)opt2 - (char*)opt;
775 memcpy(opt2, opt, opt->tot_len);
776 if (opt2->hopopt)
777 *((char**)&opt2->hopopt) += dif;
778 if (opt2->dst0opt)
779 *((char**)&opt2->dst0opt) += dif;
780 if (opt2->dst1opt)
781 *((char**)&opt2->dst1opt) += dif;
782 if (opt2->srcrt)
783 *((char**)&opt2->srcrt) += dif;
784 }
785 return opt2;
786}
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900787
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800788EXPORT_SYMBOL_GPL(ipv6_dup_options);
789
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900790static int ipv6_renew_option(void *ohdr,
791 struct ipv6_opt_hdr __user *newopt, int newoptlen,
792 int inherit,
793 struct ipv6_opt_hdr **hdr,
794 char **p)
795{
796 if (inherit) {
797 if (ohdr) {
798 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
799 *hdr = (struct ipv6_opt_hdr *)*p;
800 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
801 }
802 } else {
803 if (newopt) {
804 if (copy_from_user(*p, newopt, newoptlen))
805 return -EFAULT;
806 *hdr = (struct ipv6_opt_hdr *)*p;
807 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
808 return -EINVAL;
809 *p += CMSG_ALIGN(newoptlen);
810 }
811 }
812 return 0;
813}
814
815struct ipv6_txoptions *
816ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
817 int newtype,
818 struct ipv6_opt_hdr __user *newopt, int newoptlen)
819{
820 int tot_len = 0;
821 char *p;
822 struct ipv6_txoptions *opt2;
823 int err;
824
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700825 if (opt) {
826 if (newtype != IPV6_HOPOPTS && opt->hopopt)
827 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
828 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
829 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
830 if (newtype != IPV6_RTHDR && opt->srcrt)
831 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
832 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
833 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
834 }
835
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900836 if (newopt && newoptlen)
837 tot_len += CMSG_ALIGN(newoptlen);
838
839 if (!tot_len)
840 return NULL;
841
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900842 tot_len += sizeof(*opt2);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900843 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
844 if (!opt2)
845 return ERR_PTR(-ENOBUFS);
846
847 memset(opt2, 0, tot_len);
848
849 opt2->tot_len = tot_len;
850 p = (char *)(opt2 + 1);
851
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700852 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900853 newtype != IPV6_HOPOPTS,
854 &opt2->hopopt, &p);
855 if (err)
856 goto out;
857
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700858 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900859 newtype != IPV6_RTHDRDSTOPTS,
860 &opt2->dst0opt, &p);
861 if (err)
862 goto out;
863
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700864 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900865 newtype != IPV6_RTHDR,
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700866 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900867 if (err)
868 goto out;
869
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700870 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900871 newtype != IPV6_DSTOPTS,
872 &opt2->dst1opt, &p);
873 if (err)
874 goto out;
875
876 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
877 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
878 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
879 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
880
881 return opt2;
882out:
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900883 sock_kfree_s(sk, opt2, opt2->tot_len);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900884 return ERR_PTR(err);
885}
886
YOSHIFUJI Hideakidf9890c2005-11-20 12:23:18 +0900887struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
888 struct ipv6_txoptions *opt)
889{
890 /*
891 * ignore the dest before srcrt unless srcrt is being included.
892 * --yoshfuji
893 */
894 if (opt && opt->dst0opt && !opt->srcrt) {
895 if (opt_space != opt) {
896 memcpy(opt_space, opt, sizeof(*opt_space));
897 opt = opt_space;
898 }
899 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
900 opt->dst0opt = NULL;
901 }
902
903 return opt;
904}
905