blob: 1cdd0f0b5d34d28ed68bf32a4e2c3012c3852605 [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 NAKAMURAc61a4042006-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
199static struct tlvtype_proc tlvprocdestopt_lst[] = {
200 /* No destination options are defined now */
201 {-1, NULL}
202};
203
Patrick McHardy951dbc82006-01-06 23:02:34 -0800204static int ipv6_destopt_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
206 struct sk_buff *skb = *skbp;
207 struct inet6_skb_parm *opt = IP6CB(skb);
208
209 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
210 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
211 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
212 kfree_skb(skb);
213 return -1;
214 }
215
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900216 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 opt->dst1 = skb->h.raw - skb->nh.raw;
218
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700219 if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
220 skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 skb->h.raw += ((skb->h.raw[1]+1)<<3);
Patrick McHardy951dbc82006-01-06 23:02:34 -0800222 opt->nhoff = opt->dst1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 return 1;
224 }
225
226 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
227 return -1;
228}
229
230static struct inet6_protocol destopt_protocol = {
231 .handler = ipv6_destopt_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700232 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233};
234
235void __init ipv6_destopt_init(void)
236{
237 if (inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS) < 0)
238 printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
239}
240
241/********************************
242 NONE header. No data in packet.
243 ********************************/
244
Patrick McHardy951dbc82006-01-06 23:02:34 -0800245static int ipv6_nodata_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246{
247 struct sk_buff *skb = *skbp;
248
249 kfree_skb(skb);
250 return 0;
251}
252
253static struct inet6_protocol nodata_protocol = {
254 .handler = ipv6_nodata_rcv,
255 .flags = INET6_PROTO_NOPOLICY,
256};
257
258void __init ipv6_nodata_init(void)
259{
260 if (inet6_add_protocol(&nodata_protocol, IPPROTO_NONE) < 0)
261 printk(KERN_ERR "ipv6_nodata_init: Could not register protocol\n");
262}
263
264/********************************
265 Routing header.
266 ********************************/
267
Patrick McHardy951dbc82006-01-06 23:02:34 -0800268static int ipv6_rthdr_rcv(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
270 struct sk_buff *skb = *skbp;
271 struct inet6_skb_parm *opt = IP6CB(skb);
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700272 struct in6_addr *addr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 struct in6_addr daddr;
274 int n, i;
275
276 struct ipv6_rt_hdr *hdr;
277 struct rt0_hdr *rthdr;
278
279 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
280 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
281 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
282 kfree_skb(skb);
283 return -1;
284 }
285
286 hdr = (struct ipv6_rt_hdr *) skb->h.raw;
287
288 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
289 skb->pkt_type != PACKET_HOST) {
290 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
291 kfree_skb(skb);
292 return -1;
293 }
294
295looped_back:
296 if (hdr->segments_left == 0) {
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700297 switch (hdr->type) {
298#ifdef CONFIG_IPV6_MIP6
299 case IPV6_SRCRT_TYPE_2:
300 /* Silently discard type 2 header unless it was
301 * processed by own
302 */
303 if (!addr) {
304 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
305 kfree_skb(skb);
306 return -1;
307 }
308 break;
309#endif
310 default:
311 break;
312 }
313
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900314 opt->lastopt = skb->h.raw - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 opt->srcrt = skb->h.raw - skb->nh.raw;
316 skb->h.raw += (hdr->hdrlen + 1) << 3;
317 opt->dst0 = opt->dst1;
318 opt->dst1 = 0;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800319 opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 return 1;
321 }
322
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700323 switch (hdr->type) {
324 case IPV6_SRCRT_TYPE_0:
325 if (hdr->hdrlen & 0x01) {
326 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
327 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
328 return -1;
329 }
330 break;
331#ifdef CONFIG_IPV6_MIP6
332 case IPV6_SRCRT_TYPE_2:
333 /* Silently discard invalid RTH type 2 */
334 if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
335 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
336 kfree_skb(skb);
337 return -1;
338 }
339 break;
340#endif
341 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
343 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
344 return -1;
345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 /*
348 * This is the routing header forwarding algorithm from
349 * RFC 2460, page 16.
350 */
351
352 n = hdr->hdrlen >> 1;
353
354 if (hdr->segments_left > n) {
355 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
356 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
357 return -1;
358 }
359
360 /* We are about to mangle packet header. Be careful!
361 Do not damage packets queued somewhere.
362 */
363 if (skb_cloned(skb)) {
364 struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
365 kfree_skb(skb);
366 /* the copy is a forwarded packet */
367 if (skb2 == NULL) {
368 IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS);
369 return -1;
370 }
371 *skbp = skb = skb2;
372 opt = IP6CB(skb2);
373 hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
374 }
375
Patrick McHardy84fa7932006-08-29 16:44:56 -0700376 if (skb->ip_summed == CHECKSUM_COMPLETE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 skb->ip_summed = CHECKSUM_NONE;
378
379 i = n - --hdr->segments_left;
380
381 rthdr = (struct rt0_hdr *) hdr;
382 addr = rthdr->addr;
383 addr += i - 1;
384
Masahide NAKAMURA65d4ed92006-08-23 19:16:22 -0700385 switch (hdr->type) {
386#ifdef CONFIG_IPV6_MIP6
387 case IPV6_SRCRT_TYPE_2:
388 if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
389 (xfrm_address_t *)&skb->nh.ipv6h->saddr,
390 IPPROTO_ROUTING) < 0) {
391 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
392 kfree_skb(skb);
393 return -1;
394 }
395 if (!ipv6_chk_home_addr(addr)) {
396 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
397 kfree_skb(skb);
398 return -1;
399 }
400 break;
401#endif
402 default:
403 break;
404 }
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if (ipv6_addr_is_multicast(addr)) {
407 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
408 kfree_skb(skb);
409 return -1;
410 }
411
412 ipv6_addr_copy(&daddr, addr);
413 ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
414 ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
415
416 dst_release(xchg(&skb->dst, NULL));
417 ip6_route_input(skb);
418 if (skb->dst->error) {
419 skb_push(skb, skb->data - skb->nh.raw);
420 dst_input(skb);
421 return -1;
422 }
423
424 if (skb->dst->dev->flags&IFF_LOOPBACK) {
425 if (skb->nh.ipv6h->hop_limit <= 1) {
426 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
427 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
428 0, skb->dev);
429 kfree_skb(skb);
430 return -1;
431 }
432 skb->nh.ipv6h->hop_limit--;
433 goto looped_back;
434 }
435
436 skb_push(skb, skb->data - skb->nh.raw);
437 dst_input(skb);
438 return -1;
439}
440
441static struct inet6_protocol rthdr_protocol = {
442 .handler = ipv6_rthdr_rcv,
Herbert Xuadcfc7d2006-06-30 13:36:15 -0700443 .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444};
445
446void __init ipv6_rthdr_init(void)
447{
448 if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)
449 printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
450};
451
452/*
453 This function inverts received rthdr.
454 NOTE: specs allow to make it automatically only if
455 packet authenticated.
456
457 I will not discuss it here (though, I am really pissed off at
458 this stupid requirement making rthdr idea useless)
459
460 Actually, it creates severe problems for us.
461 Embryonic requests has no associated sockets,
462 so that user have no control over it and
463 cannot not only to set reply options, but
464 even to know, that someone wants to connect
465 without success. :-(
466
467 For now we need to test the engine, so that I created
468 temporary (or permanent) backdoor.
469 If listening socket set IPV6_RTHDR to 2, then we invert header.
470 --ANK (980729)
471 */
472
473struct ipv6_txoptions *
474ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
475{
476 /* Received rthdr:
477
478 [ H1 -> H2 -> ... H_prev ] daddr=ME
479
480 Inverted result:
481 [ H_prev -> ... -> H1 ] daddr =sender
482
483 Note, that IP output engine will rewrite this rthdr
484 by rotating it left by one addr.
485 */
486
487 int n, i;
488 struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
489 struct rt0_hdr *irthdr;
490 struct ipv6_txoptions *opt;
491 int hdrlen = ipv6_optlen(hdr);
492
493 if (hdr->segments_left ||
494 hdr->type != IPV6_SRCRT_TYPE_0 ||
495 hdr->hdrlen & 0x01)
496 return NULL;
497
498 n = hdr->hdrlen >> 1;
499 opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
500 if (opt == NULL)
501 return NULL;
502 memset(opt, 0, sizeof(*opt));
503 opt->tot_len = sizeof(*opt) + hdrlen;
504 opt->srcrt = (void*)(opt+1);
505 opt->opt_nflen = hdrlen;
506
507 memcpy(opt->srcrt, hdr, sizeof(*hdr));
508 irthdr = (struct rt0_hdr*)opt->srcrt;
Brian Haleye6df4392005-09-10 00:15:06 -0700509 irthdr->reserved = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 opt->srcrt->segments_left = n;
511 for (i=0; i<n; i++)
512 memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
513 return opt;
514}
515
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800516EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/**********************************
519 Hop-by-hop options.
520 **********************************/
521
522/* Router Alert as of RFC 2711 */
523
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700524static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700526 struct sk_buff *skb = *skbp;
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 if (skb->nh.raw[optoff+1] == 2) {
529 IP6CB(skb)->ra = optoff;
530 return 1;
531 }
Patrick McHardy64ce2072005-08-09 20:50:53 -0700532 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
533 skb->nh.raw[optoff+1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 kfree_skb(skb);
535 return 0;
536}
537
538/* Jumbo payload */
539
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700540static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700542 struct sk_buff *skb = *skbp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 u32 pkt_len;
544
545 if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
Patrick McHardy64ce2072005-08-09 20:50:53 -0700546 LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
547 skb->nh.raw[optoff+1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
549 goto drop;
550 }
551
552 pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
553 if (pkt_len <= IPV6_MAXPLEN) {
554 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
555 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
556 return 0;
557 }
558 if (skb->nh.ipv6h->payload_len) {
559 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
560 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
561 return 0;
562 }
563
564 if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
565 IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
566 goto drop;
567 }
Stephen Hemminger42ca89c2005-09-08 12:57:43 -0700568
569 if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
570 goto drop;
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return 1;
573
574drop:
575 kfree_skb(skb);
576 return 0;
577}
578
579static struct tlvtype_proc tlvprochopopt_lst[] = {
580 {
581 .type = IPV6_TLV_ROUTERALERT,
582 .func = ipv6_hop_ra,
583 },
584 {
585 .type = IPV6_TLV_JUMBO,
586 .func = ipv6_hop_jumbo,
587 },
588 { -1, }
589};
590
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700591int ipv6_parse_hopopts(struct sk_buff **skbp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700593 struct sk_buff *skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800594 struct inet6_skb_parm *opt = IP6CB(skb);
595
YOSHIFUJI Hideakiec670092006-04-18 14:46:26 -0700596 /*
597 * skb->nh.raw is equal to skb->data, and
598 * skb->h.raw - skb->nh.raw is always equal to
599 * sizeof(struct ipv6hdr) by definition of
600 * hop-by-hop options.
601 */
602 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
603 !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
604 kfree_skb(skb);
605 return -1;
606 }
607
Patrick McHardy951dbc82006-01-06 23:02:34 -0800608 opt->hop = sizeof(struct ipv6hdr);
Masahide NAKAMURAa80ff032006-08-23 19:19:50 -0700609 if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
610 skb = *skbp;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800611 skb->h.raw += (skb->h.raw[1]+1)<<3;
612 opt->nhoff = sizeof(struct ipv6hdr);
YOSHIFUJI Hideakib8097392006-04-18 14:48:45 -0700613 return 1;
Patrick McHardy951dbc82006-01-06 23:02:34 -0800614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return -1;
616}
617
618/*
619 * Creating outbound headers.
620 *
621 * "build" functions work when skb is filled from head to tail (datagram)
622 * "push" functions work when headers are added from tail to head (tcp)
623 *
624 * In both cases we assume, that caller reserved enough room
625 * for headers.
626 */
627
628static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
629 struct ipv6_rt_hdr *opt,
630 struct in6_addr **addr_p)
631{
632 struct rt0_hdr *phdr, *ihdr;
633 int hops;
634
635 ihdr = (struct rt0_hdr *) opt;
636
637 phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
638 memcpy(phdr, ihdr, sizeof(struct rt0_hdr));
639
640 hops = ihdr->rt_hdr.hdrlen >> 1;
641
642 if (hops > 1)
643 memcpy(phdr->addr, ihdr->addr + 1,
644 (hops - 1) * sizeof(struct in6_addr));
645
646 ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
647 *addr_p = ihdr->addr;
648
649 phdr->rt_hdr.nexthdr = *proto;
650 *proto = NEXTHDR_ROUTING;
651}
652
653static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
654{
655 struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));
656
657 memcpy(h, opt, ipv6_optlen(opt));
658 h->nexthdr = *proto;
659 *proto = type;
660}
661
662void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
663 u8 *proto,
664 struct in6_addr **daddr)
665{
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900666 if (opt->srcrt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900668 /*
669 * IPV6_RTHDRDSTOPTS is ignored
670 * unless IPV6_RTHDR is set (RFC3542).
671 */
672 if (opt->dst0opt)
673 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (opt->hopopt)
676 ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
677}
678
679void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
680{
681 if (opt->dst1opt)
682 ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
683}
684
685struct ipv6_txoptions *
686ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
687{
688 struct ipv6_txoptions *opt2;
689
690 opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
691 if (opt2) {
692 long dif = (char*)opt2 - (char*)opt;
693 memcpy(opt2, opt, opt->tot_len);
694 if (opt2->hopopt)
695 *((char**)&opt2->hopopt) += dif;
696 if (opt2->dst0opt)
697 *((char**)&opt2->dst0opt) += dif;
698 if (opt2->dst1opt)
699 *((char**)&opt2->dst1opt) += dif;
700 if (opt2->srcrt)
701 *((char**)&opt2->srcrt) += dif;
702 }
703 return opt2;
704}
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900705
Arnaldo Carvalho de Melo3cf3dc62005-12-13 23:23:20 -0800706EXPORT_SYMBOL_GPL(ipv6_dup_options);
707
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900708static int ipv6_renew_option(void *ohdr,
709 struct ipv6_opt_hdr __user *newopt, int newoptlen,
710 int inherit,
711 struct ipv6_opt_hdr **hdr,
712 char **p)
713{
714 if (inherit) {
715 if (ohdr) {
716 memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
717 *hdr = (struct ipv6_opt_hdr *)*p;
718 *p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
719 }
720 } else {
721 if (newopt) {
722 if (copy_from_user(*p, newopt, newoptlen))
723 return -EFAULT;
724 *hdr = (struct ipv6_opt_hdr *)*p;
725 if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
726 return -EINVAL;
727 *p += CMSG_ALIGN(newoptlen);
728 }
729 }
730 return 0;
731}
732
733struct ipv6_txoptions *
734ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
735 int newtype,
736 struct ipv6_opt_hdr __user *newopt, int newoptlen)
737{
738 int tot_len = 0;
739 char *p;
740 struct ipv6_txoptions *opt2;
741 int err;
742
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700743 if (opt) {
744 if (newtype != IPV6_HOPOPTS && opt->hopopt)
745 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
746 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
747 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
748 if (newtype != IPV6_RTHDR && opt->srcrt)
749 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
750 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
751 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
752 }
753
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900754 if (newopt && newoptlen)
755 tot_len += CMSG_ALIGN(newoptlen);
756
757 if (!tot_len)
758 return NULL;
759
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900760 tot_len += sizeof(*opt2);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900761 opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
762 if (!opt2)
763 return ERR_PTR(-ENOBUFS);
764
765 memset(opt2, 0, tot_len);
766
767 opt2->tot_len = tot_len;
768 p = (char *)(opt2 + 1);
769
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700770 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900771 newtype != IPV6_HOPOPTS,
772 &opt2->hopopt, &p);
773 if (err)
774 goto out;
775
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700776 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900777 newtype != IPV6_RTHDRDSTOPTS,
778 &opt2->dst0opt, &p);
779 if (err)
780 goto out;
781
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700782 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900783 newtype != IPV6_RTHDR,
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700784 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900785 if (err)
786 goto out;
787
YOSHIFUJI Hideaki99c7bc02006-08-31 14:52:17 -0700788 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900789 newtype != IPV6_DSTOPTS,
790 &opt2->dst1opt, &p);
791 if (err)
792 goto out;
793
794 opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
795 (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
796 (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
797 opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
798
799 return opt2;
800out:
YOSHIFUJI Hideaki8b8aa4b2005-11-20 12:18:17 +0900801 sock_kfree_s(sk, opt2, opt2->tot_len);
YOSHIFUJI Hideaki333fad52005-09-08 09:59:17 +0900802 return ERR_PTR(err);
803}
804
YOSHIFUJI Hideakidf9890c2005-11-20 12:23:18 +0900805struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
806 struct ipv6_txoptions *opt)
807{
808 /*
809 * ignore the dest before srcrt unless srcrt is being included.
810 * --yoshfuji
811 */
812 if (opt && opt->dst0opt && !opt->srcrt) {
813 if (opt_space != opt) {
814 memcpy(opt_space, opt, sizeof(*opt_space));
815 opt = opt_space;
816 }
817 opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
818 opt->dst0opt = NULL;
819 }
820
821 return opt;
822}
823