exthdrs.c 20.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *	Extension Header handling for IPv6
 *	Linux INET6 implementation
 *
 *	Authors:
 *	Pedro Roque		<roque@di.fc.ul.pt>
 *	Andi Kleen		<ak@muc.de>
 *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
 *
 *	This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */

/* Changes:
17
 *	yoshfuji		: ensure not to overrun while parsing
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31
 *				  tlv options.
 *	Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs().
 *	YOSHIFUJI Hideaki @USAGI  Register inbound extension header
 *				  handlers as inet6_protocol{}.
 */

#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/icmpv6.h>
32
#include <linux/slab.h>
L
Linus Torvalds 已提交
33

34
#include <net/dst.h>
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43 44
#include <net/sock.h>
#include <net/snmp.h>

#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/transp_v6.h>
#include <net/rawv6.h>
#include <net/ndisc.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
45
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
46 47
#include <net/xfrm.h>
#endif
L
Linus Torvalds 已提交
48 49 50

#include <asm/uaccess.h>

51 52
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 56 57 58 59
	struct ipv6_opt_hdr *hdr;
	int len;

	if (offset + 2 > packet_len)
		goto bad;
60
	hdr = (struct ipv6_opt_hdr *)(nh + offset);
61 62 63 64 65 66 67 68 69
	len = ((hdr->hdrlen + 1) << 3);

	if (offset + len > packet_len)
		goto bad;

	offset += 2;
	len -= 2;

	while (len > 0) {
70
		int opttype = nh[offset];
71 72 73 74 75 76 77 78 79 80
		int optlen;

		if (opttype == type)
			return offset;

		switch (opttype) {
		case IPV6_TLV_PAD0:
			optlen = 1;
			break;
		default:
81
			optlen = nh[offset + 1] + 2;
82 83 84 85 86 87 88 89 90 91 92
			if (optlen > len)
				goto bad;
			break;
		}
		offset += optlen;
		len -= optlen;
	}
	/* not_found */
 bad:
	return -1;
}
93
EXPORT_SYMBOL_GPL(ipv6_find_tlv);
94

L
Linus Torvalds 已提交
95 96 97 98 99 100 101 102 103 104
/*
 *	Parsing tlv encoded headers.
 *
 *	Parsing function "func" returns 1, if parsing succeed
 *	and 0, if it failed.
 *	It MUST NOT touch skb->h.
 */

struct tlvtype_proc {
	int	type;
105
	int	(*func)(struct sk_buff *skb, int offset);
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113
};

/*********************
  Generic functions
 *********************/

/* An unknown option is detected, decide what to do */

114
static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff)
L
Linus Torvalds 已提交
115
{
116
	switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
L
Linus Torvalds 已提交
117 118 119 120 121 122 123 124 125 126
	case 0: /* ignore */
		return 1;

	case 1: /* drop packet */
		break;

	case 3: /* Send ICMP if not a multicast address and drop packet */
		/* Actually, it is redundant check. icmp_send
		   will recheck in any case.
		 */
127
		if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
L
Linus Torvalds 已提交
128 129 130 131
			break;
	case 2: /* send ICMP PARM PROB regardless and drop packet */
		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
		return 0;
132
	}
L
Linus Torvalds 已提交
133 134 135 136 137 138 139

	kfree_skb(skb);
	return 0;
}

/* Parse tlv encoded option header (hop-by-hop or destination) */

140
static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb)
L
Linus Torvalds 已提交
141 142
{
	struct tlvtype_proc *curr;
143
	const unsigned char *nh = skb_network_header(skb);
144
	int off = skb_network_header_len(skb);
145
	int len = (skb_transport_header(skb)[1] + 1) << 3;
L
Linus Torvalds 已提交
146

147
	if (skb_transport_offset(skb) + len > skb_headlen(skb))
L
Linus Torvalds 已提交
148 149 150 151 152 153
		goto bad;

	off += 2;
	len -= 2;

	while (len > 0) {
154
		int optlen = nh[off + 1] + 2;
L
Linus Torvalds 已提交
155

156
		switch (nh[off]) {
L
Linus Torvalds 已提交
157 158 159 160 161 162 163 164 165 166 167
		case IPV6_TLV_PAD0:
			optlen = 1;
			break;

		case IPV6_TLV_PADN:
			break;

		default: /* Other TLV code so scan list */
			if (optlen > len)
				goto bad;
			for (curr=procs; curr->type >= 0; curr++) {
168
				if (curr->type == nh[off]) {
169 170
					/* type specific length/alignment
					   checks will be performed in the
L
Linus Torvalds 已提交
171
					   func(). */
172
					if (curr->func(skb, off) == 0)
L
Linus Torvalds 已提交
173 174 175 176 177
						return 0;
					break;
				}
			}
			if (curr->type < 0) {
178
				if (ip6_tlvopt_unknown(skb, off) == 0)
L
Linus Torvalds 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
					return 0;
			}
			break;
		}
		off += optlen;
		len -= optlen;
	}
	if (len == 0)
		return 1;
bad:
	kfree_skb(skb);
	return 0;
}

/*****************************
  Destination options header.
 *****************************/

197
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
198
static int ipv6_dest_hao(struct sk_buff *skb, int optoff)
199 200 201
{
	struct ipv6_destopt_hao *hao;
	struct inet6_skb_parm *opt = IP6CB(skb);
202
	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
203 204 205 206 207 208 209 210 211 212
	struct in6_addr tmp_addr;
	int ret;

	if (opt->dsthao) {
		LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n");
		goto discard;
	}
	opt->dsthao = opt->dst1;
	opt->dst1 = 0;

213
	hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
214 215 216 217 218 219 220 221 222

	if (hao->length != 16) {
		LIMIT_NETDEBUG(
			KERN_DEBUG "hao invalid option length = %d\n", hao->length);
		goto discard;
	}

	if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
		LIMIT_NETDEBUG(
H
Harvey Harrison 已提交
223
			KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr);
224 225 226 227 228 229 230 231 232
		goto discard;
	}

	ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
			       (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
	if (unlikely(ret < 0))
		goto discard;

	if (skb_cloned(skb)) {
233
		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
234 235 236
			goto discard;

		/* update all variable using below by copied skbuff */
237
		hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
238
						  optoff);
239
		ipv6h = ipv6_hdr(skb);
240 241 242 243 244 245 246 247 248
	}

	if (skb->ip_summed == CHECKSUM_COMPLETE)
		skb->ip_summed = CHECKSUM_NONE;

	ipv6_addr_copy(&tmp_addr, &ipv6h->saddr);
	ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
	ipv6_addr_copy(&hao->addr, &tmp_addr);

249
	if (skb->tstamp.tv64 == 0)
250 251 252 253 254 255 256 257 258 259
		__net_timestamp(skb);

	return 1;

 discard:
	kfree_skb(skb);
	return 0;
}
#endif

L
Linus Torvalds 已提交
260
static struct tlvtype_proc tlvprocdestopt_lst[] = {
261
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
262 263 264 265 266
	{
		.type	= IPV6_TLV_HAO,
		.func	= ipv6_dest_hao,
	},
#endif
L
Linus Torvalds 已提交
267 268 269
	{-1,			NULL}
};

270
static int ipv6_destopt_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
271 272
{
	struct inet6_skb_parm *opt = IP6CB(skb);
273
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
274 275
	__u16 dstbuf;
#endif
276
	struct dst_entry *dst;
L
Linus Torvalds 已提交
277

278 279
	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
280
				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
E
Eric Dumazet 已提交
281
		IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
282
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
283 284 285 286
		kfree_skb(skb);
		return -1;
	}

287
	opt->lastopt = opt->dst1 = skb_network_header_len(skb);
288
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
289 290
	dstbuf = opt->dst1;
#endif
L
Linus Torvalds 已提交
291

E
Eric Dumazet 已提交
292
	dst = dst_clone(skb_dst(skb));
293
	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
294
		dst_release(dst);
295
		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
296
		opt = IP6CB(skb);
297
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
298 299
		opt->nhoff = dstbuf;
#else
300
		opt->nhoff = opt->dst1;
301
#endif
L
Linus Torvalds 已提交
302 303 304
		return 1;
	}

305 306
	IP6_INC_STATS_BH(dev_net(dst->dev),
			 ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
307
	dst_release(dst);
L
Linus Torvalds 已提交
308 309 310 311 312 313 314
	return -1;
}

/********************************
  Routing header.
 ********************************/

315
static int ipv6_rthdr_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
316 317
{
	struct inet6_skb_parm *opt = IP6CB(skb);
318
	struct in6_addr *addr = NULL;
L
Linus Torvalds 已提交
319
	struct in6_addr daddr;
320
	struct inet6_dev *idev;
L
Linus Torvalds 已提交
321 322 323
	int n, i;
	struct ipv6_rt_hdr *hdr;
	struct rt0_hdr *rthdr;
324 325
	struct net *net = dev_net(skb->dev);
	int accept_source_route = net->ipv6.devconf_all->accept_source_route;
326

327 328 329 330
	idev = in6_dev_get(skb->dev);
	if (idev) {
		if (accept_source_route > idev->cnf.accept_source_route)
			accept_source_route = idev->cnf.accept_source_route;
331 332 333
		in6_dev_put(idev);
	}

334 335
	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
336
				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
E
Eric Dumazet 已提交
337
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
338
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
339 340 341 342
		kfree_skb(skb);
		return -1;
	}

343
	hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
L
Linus Torvalds 已提交
344

345
	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
L
Linus Torvalds 已提交
346
	    skb->pkt_type != PACKET_HOST) {
E
Eric Dumazet 已提交
347
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
348
				 IPSTATS_MIB_INADDRERRORS);
L
Linus Torvalds 已提交
349 350 351 352 353 354
		kfree_skb(skb);
		return -1;
	}

looped_back:
	if (hdr->segments_left == 0) {
355
		switch (hdr->type) {
356
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
357 358 359 360 361
		case IPV6_SRCRT_TYPE_2:
			/* Silently discard type 2 header unless it was
			 * processed by own
			 */
			if (!addr) {
E
Eric Dumazet 已提交
362
				IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
363
						 IPSTATS_MIB_INADDRERRORS);
364 365 366 367 368 369 370 371 372
				kfree_skb(skb);
				return -1;
			}
			break;
#endif
		default:
			break;
		}

373
		opt->lastopt = opt->srcrt = skb_network_header_len(skb);
374
		skb->transport_header += (hdr->hdrlen + 1) << 3;
L
Linus Torvalds 已提交
375 376
		opt->dst0 = opt->dst1;
		opt->dst1 = 0;
377
		opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
L
Linus Torvalds 已提交
378 379 380
		return 1;
	}

381
	switch (hdr->type) {
382
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
383
	case IPV6_SRCRT_TYPE_2:
384 385
		if (accept_source_route < 0)
			goto unknown_rh;
386 387
		/* Silently discard invalid RTH type 2 */
		if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
E
Eric Dumazet 已提交
388
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
389
					 IPSTATS_MIB_INHDRERRORS);
390 391 392 393 394
			kfree_skb(skb);
			return -1;
		}
		break;
#endif
395 396
	default:
		goto unknown_rh;
L
Linus Torvalds 已提交
397 398 399 400 401 402 403 404 405 406
	}

	/*
	 *	This is the routing header forwarding algorithm from
	 *	RFC 2460, page 16.
	 */

	n = hdr->hdrlen >> 1;

	if (hdr->segments_left > n) {
E
Eric Dumazet 已提交
407
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
408
				 IPSTATS_MIB_INHDRERRORS);
409 410 411
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
				  ((&hdr->segments_left) -
				   skb_network_header(skb)));
L
Linus Torvalds 已提交
412 413 414 415 416 417 418 419
		return -1;
	}

	/* We are about to mangle packet header. Be careful!
	   Do not damage packets queued somewhere.
	 */
	if (skb_cloned(skb)) {
		/* the copy is a forwarded packet */
420
		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
E
Eric Dumazet 已提交
421
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
422 423
					 IPSTATS_MIB_OUTDISCARDS);
			kfree_skb(skb);
L
Linus Torvalds 已提交
424 425
			return -1;
		}
426
		hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
L
Linus Torvalds 已提交
427 428
	}

429
	if (skb->ip_summed == CHECKSUM_COMPLETE)
L
Linus Torvalds 已提交
430 431 432 433 434 435 436 437
		skb->ip_summed = CHECKSUM_NONE;

	i = n - --hdr->segments_left;

	rthdr = (struct rt0_hdr *) hdr;
	addr = rthdr->addr;
	addr += i - 1;

438
	switch (hdr->type) {
439
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
440 441
	case IPV6_SRCRT_TYPE_2:
		if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
442
				     (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
443
				     IPPROTO_ROUTING) < 0) {
E
Eric Dumazet 已提交
444
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
445
					 IPSTATS_MIB_INADDRERRORS);
446 447 448
			kfree_skb(skb);
			return -1;
		}
E
Eric Dumazet 已提交
449 450
		if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
451
					 IPSTATS_MIB_INADDRERRORS);
452 453 454 455 456 457 458 459 460
			kfree_skb(skb);
			return -1;
		}
		break;
#endif
	default:
		break;
	}

L
Linus Torvalds 已提交
461
	if (ipv6_addr_is_multicast(addr)) {
E
Eric Dumazet 已提交
462
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
463
				 IPSTATS_MIB_INADDRERRORS);
L
Linus Torvalds 已提交
464 465 466 467 468
		kfree_skb(skb);
		return -1;
	}

	ipv6_addr_copy(&daddr, addr);
469 470
	ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);
	ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);
L
Linus Torvalds 已提交
471

E
Eric Dumazet 已提交
472
	skb_dst_drop(skb);
L
Linus Torvalds 已提交
473
	ip6_route_input(skb);
E
Eric Dumazet 已提交
474
	if (skb_dst(skb)->error) {
475
		skb_push(skb, skb->data - skb_network_header(skb));
L
Linus Torvalds 已提交
476 477 478 479
		dst_input(skb);
		return -1;
	}

E
Eric Dumazet 已提交
480
	if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
481
		if (ipv6_hdr(skb)->hop_limit <= 1) {
E
Eric Dumazet 已提交
482
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
483
					 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
484
			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
485
				    0);
L
Linus Torvalds 已提交
486 487 488
			kfree_skb(skb);
			return -1;
		}
489
		ipv6_hdr(skb)->hop_limit--;
L
Linus Torvalds 已提交
490 491 492
		goto looped_back;
	}

493
	skb_push(skb, skb->data - skb_network_header(skb));
L
Linus Torvalds 已提交
494 495
	dst_input(skb);
	return -1;
496 497

unknown_rh:
E
Eric Dumazet 已提交
498
	IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
499 500 501
	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
			  (&hdr->type) - skb_network_header(skb));
	return -1;
L
Linus Torvalds 已提交
502 503
}

504
static const struct inet6_protocol rthdr_protocol = {
L
Linus Torvalds 已提交
505
	.handler	=	ipv6_rthdr_rcv,
H
Herbert Xu 已提交
506
	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
L
Linus Torvalds 已提交
507 508
};

509
static const struct inet6_protocol destopt_protocol = {
510 511 512 513
	.handler	=	ipv6_destopt_rcv,
	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
};

514
static const struct inet6_protocol nodata_protocol = {
515 516 517 518 519
	.handler	=	dst_discard,
	.flags		=	INET6_PROTO_NOPOLICY,
};

int __init ipv6_exthdrs_init(void)
L
Linus Torvalds 已提交
520
{
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
	int ret;

	ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
	if (ret)
		goto out;

	ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
	if (ret)
		goto out_rthdr;

	ret = inet6_add_protocol(&nodata_protocol, IPPROTO_NONE);
	if (ret)
		goto out_destopt;

out:
	return ret;
out_rthdr:
	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
out_destopt:
	inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
	goto out;
L
Linus Torvalds 已提交
542 543
};

544 545 546 547 548 549 550
void ipv6_exthdrs_exit(void)
{
	inet6_del_protocol(&nodata_protocol, IPPROTO_NONE);
	inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
	inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
}

L
Linus Torvalds 已提交
551 552 553 554
/**********************************
  Hop-by-hop options.
 **********************************/

555
/*
E
Eric Dumazet 已提交
556
 * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input().
557 558 559
 */
static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
{
E
Eric Dumazet 已提交
560
	return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev);
561 562
}

563 564 565 566 567
static inline struct net *ipv6_skb_net(struct sk_buff *skb)
{
	return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev);
}

L
Linus Torvalds 已提交
568 569
/* Router Alert as of RFC 2711 */

570
static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
L
Linus Torvalds 已提交
571
{
572
	const unsigned char *nh = skb_network_header(skb);
573

574
	if (nh[optoff + 1] == 2) {
L
Linus Torvalds 已提交
575 576 577
		IP6CB(skb)->ra = optoff;
		return 1;
	}
578
	LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
579
		       nh[optoff + 1]);
L
Linus Torvalds 已提交
580 581 582 583 584 585
	kfree_skb(skb);
	return 0;
}

/* Jumbo payload */

586
static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
L
Linus Torvalds 已提交
587
{
588
	const unsigned char *nh = skb_network_header(skb);
589
	struct net *net = ipv6_skb_net(skb);
L
Linus Torvalds 已提交
590 591
	u32 pkt_len;

592
	if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
593
		LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
594
			       nh[optoff+1]);
595
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
596
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
597 598 599
		goto drop;
	}

600
	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
L
Linus Torvalds 已提交
601
	if (pkt_len <= IPV6_MAXPLEN) {
602 603
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
604 605 606
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
		return 0;
	}
607
	if (ipv6_hdr(skb)->payload_len) {
608 609
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
610 611 612 613 614
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
		return 0;
	}

	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
615 616
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
				 IPSTATS_MIB_INTRUNCATEDPKTS);
L
Linus Torvalds 已提交
617 618
		goto drop;
	}
619 620 621 622

	if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
		goto drop;

L
Linus Torvalds 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
	return 1;

drop:
	kfree_skb(skb);
	return 0;
}

static struct tlvtype_proc tlvprochopopt_lst[] = {
	{
		.type	= IPV6_TLV_ROUTERALERT,
		.func	= ipv6_hop_ra,
	},
	{
		.type	= IPV6_TLV_JUMBO,
		.func	= ipv6_hop_jumbo,
	},
	{ -1, }
};

642
int ipv6_parse_hopopts(struct sk_buff *skb)
L
Linus Torvalds 已提交
643
{
644 645
	struct inet6_skb_parm *opt = IP6CB(skb);

646
	/*
647
	 * skb_network_header(skb) is equal to skb->data, and
648
	 * skb_network_header_len(skb) is always equal to
649 650 651 652
	 * sizeof(struct ipv6hdr) by definition of
	 * hop-by-hop options.
	 */
	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
653 654
	    !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
655 656 657 658
		kfree_skb(skb);
		return -1;
	}

659
	opt->hop = sizeof(struct ipv6hdr);
660
	if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
661
		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
662
		opt = IP6CB(skb);
663
		opt->nhoff = sizeof(struct ipv6hdr);
664
		return 1;
665
	}
L
Linus Torvalds 已提交
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
	return -1;
}

/*
 *	Creating outbound headers.
 *
 *	"build" functions work when skb is filled from head to tail (datagram)
 *	"push"	functions work when headers are added from tail to head (tcp)
 *
 *	In both cases we assume, that caller reserved enough room
 *	for headers.
 */

static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
			    struct ipv6_rt_hdr *opt,
			    struct in6_addr **addr_p)
{
	struct rt0_hdr *phdr, *ihdr;
	int hops;

	ihdr = (struct rt0_hdr *) opt;
687

L
Linus Torvalds 已提交
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
	phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);
	memcpy(phdr, ihdr, sizeof(struct rt0_hdr));

	hops = ihdr->rt_hdr.hdrlen >> 1;

	if (hops > 1)
		memcpy(phdr->addr, ihdr->addr + 1,
		       (hops - 1) * sizeof(struct in6_addr));

	ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);
	*addr_p = ihdr->addr;

	phdr->rt_hdr.nexthdr = *proto;
	*proto = NEXTHDR_ROUTING;
}

static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
{
	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));

	memcpy(h, opt, ipv6_optlen(opt));
	h->nexthdr = *proto;
	*proto = type;
}

void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
			  u8 *proto,
			  struct in6_addr **daddr)
{
717
	if (opt->srcrt) {
L
Linus Torvalds 已提交
718
		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
719 720 721 722 723 724 725
		/*
		 * IPV6_RTHDRDSTOPTS is ignored
		 * unless IPV6_RTHDR is set (RFC3542).
		 */
		if (opt->dst0opt)
			ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
	}
L
Linus Torvalds 已提交
726 727 728 729
	if (opt->hopopt)
		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
}

730 731
EXPORT_SYMBOL(ipv6_push_nfrag_opts);

L
Linus Torvalds 已提交
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
{
	if (opt->dst1opt)
		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
}

struct ipv6_txoptions *
ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
{
	struct ipv6_txoptions *opt2;

	opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
	if (opt2) {
		long dif = (char*)opt2 - (char*)opt;
		memcpy(opt2, opt, opt->tot_len);
		if (opt2->hopopt)
			*((char**)&opt2->hopopt) += dif;
		if (opt2->dst0opt)
			*((char**)&opt2->dst0opt) += dif;
		if (opt2->dst1opt)
			*((char**)&opt2->dst1opt) += dif;
		if (opt2->srcrt)
			*((char**)&opt2->srcrt) += dif;
	}
	return opt2;
}
758

759 760
EXPORT_SYMBOL_GPL(ipv6_dup_options);

761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
static int ipv6_renew_option(void *ohdr,
			     struct ipv6_opt_hdr __user *newopt, int newoptlen,
			     int inherit,
			     struct ipv6_opt_hdr **hdr,
			     char **p)
{
	if (inherit) {
		if (ohdr) {
			memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));
			*hdr = (struct ipv6_opt_hdr *)*p;
			*p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));
		}
	} else {
		if (newopt) {
			if (copy_from_user(*p, newopt, newoptlen))
				return -EFAULT;
			*hdr = (struct ipv6_opt_hdr *)*p;
			if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)
				return -EINVAL;
			*p += CMSG_ALIGN(newoptlen);
		}
	}
	return 0;
}

struct ipv6_txoptions *
ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
		   int newtype,
		   struct ipv6_opt_hdr __user *newopt, int newoptlen)
{
	int tot_len = 0;
	char *p;
	struct ipv6_txoptions *opt2;
	int err;

796 797 798 799 800 801 802 803 804 805 806
	if (opt) {
		if (newtype != IPV6_HOPOPTS && opt->hopopt)
			tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
		if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
			tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
		if (newtype != IPV6_RTHDR && opt->srcrt)
			tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
		if (newtype != IPV6_DSTOPTS && opt->dst1opt)
			tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
	}

807 808 809 810 811 812
	if (newopt && newoptlen)
		tot_len += CMSG_ALIGN(newoptlen);

	if (!tot_len)
		return NULL;

813
	tot_len += sizeof(*opt2);
814 815 816 817 818 819 820 821 822
	opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
	if (!opt2)
		return ERR_PTR(-ENOBUFS);

	memset(opt2, 0, tot_len);

	opt2->tot_len = tot_len;
	p = (char *)(opt2 + 1);

823
	err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
824 825 826 827 828
				newtype != IPV6_HOPOPTS,
				&opt2->hopopt, &p);
	if (err)
		goto out;

829
	err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
830 831 832 833 834
				newtype != IPV6_RTHDRDSTOPTS,
				&opt2->dst0opt, &p);
	if (err)
		goto out;

835
	err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
836
				newtype != IPV6_RTHDR,
837
				(struct ipv6_opt_hdr **)&opt2->srcrt, &p);
838 839 840
	if (err)
		goto out;

841
	err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
842 843 844 845 846 847 848 849 850 851 852 853
				newtype != IPV6_DSTOPTS,
				&opt2->dst1opt, &p);
	if (err)
		goto out;

	opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
			  (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
			  (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
	opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);

	return opt2;
out:
854
	sock_kfree_s(sk, opt2, opt2->tot_len);
855 856 857
	return ERR_PTR(err);
}

858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
					  struct ipv6_txoptions *opt)
{
	/*
	 * ignore the dest before srcrt unless srcrt is being included.
	 * --yoshfuji
	 */
	if (opt && opt->dst0opt && !opt->srcrt) {
		if (opt_space != opt) {
			memcpy(opt_space, opt, sizeof(*opt_space));
			opt = opt_space;
		}
		opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
		opt->dst0opt = NULL;
	}

	return opt;
}