exthdrs.c 21.9 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>
33
#include <linux/export.h>
L
Linus Torvalds 已提交
34

35
#include <net/dst.h>
L
Linus Torvalds 已提交
36 37 38 39 40 41 42 43 44 45
#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>
46
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
47 48
#include <net/xfrm.h>
#endif
L
Linus Torvalds 已提交
49 50 51

#include <asm/uaccess.h>

52 53
int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
{
54
	const unsigned char *nh = skb_network_header(skb);
55
	int packet_len = skb->tail - skb->network_header;
56 57 58 59 60
	struct ipv6_opt_hdr *hdr;
	int len;

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

	if (offset + len > packet_len)
		goto bad;

	offset += 2;
	len -= 2;

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

		if (opttype == type)
			return offset;

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

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

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

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

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

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

	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.
		 */
128
		if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
L
Linus Torvalds 已提交
129 130 131
			break;
	case 2: /* send ICMP PARM PROB regardless and drop packet */
		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
132
		return false;
133
	}
L
Linus Torvalds 已提交
134 135

	kfree_skb(skb);
136
	return false;
L
Linus Torvalds 已提交
137 138 139 140
}

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

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

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

	off += 2;
	len -= 2;

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

159
		switch (nh[off]) {
160
		case IPV6_TLV_PAD1:
L
Linus Torvalds 已提交
161
			optlen = 1;
162 163 164
			padlen++;
			if (padlen > 7)
				goto bad;
L
Linus Torvalds 已提交
165 166 167
			break;

		case IPV6_TLV_PADN:
168 169 170 171 172
			/* RFC 2460 states that the purpose of PadN is
			 * to align the containing header to multiples
			 * of 8. 7 is therefore the highest valid value.
			 * See also RFC 4942, Section 2.1.9.5.
			 */
173 174
			padlen += optlen;
			if (padlen > 7)
175 176 177 178 179 180 181 182 183
				goto bad;
			/* RFC 4942 recommends receiving hosts to
			 * actively check PadN payload to contain
			 * only zeroes.
			 */
			for (i = 2; i < optlen; i++) {
				if (nh[off + i] != 0)
					goto bad;
			}
L
Linus Torvalds 已提交
184 185 186 187 188 189
			break;

		default: /* Other TLV code so scan list */
			if (optlen > len)
				goto bad;
			for (curr=procs; curr->type >= 0; curr++) {
190
				if (curr->type == nh[off]) {
191 192
					/* type specific length/alignment
					   checks will be performed in the
L
Linus Torvalds 已提交
193
					   func(). */
194 195
					if (curr->func(skb, off) == false)
						return false;
L
Linus Torvalds 已提交
196 197 198 199
					break;
				}
			}
			if (curr->type < 0) {
200
				if (ip6_tlvopt_unknown(skb, off) == 0)
201
					return false;
L
Linus Torvalds 已提交
202
			}
203
			padlen = 0;
L
Linus Torvalds 已提交
204 205 206 207 208
			break;
		}
		off += optlen;
		len -= optlen;
	}
209 210 211 212 213 214 215
	/* This case will not be caught by above check since its padding
	 * length is smaller than 7:
	 * 1 byte NH + 1 byte Length + 6 bytes Padding
	 */
	if ((padlen == 6) && ((off - skb_network_header_len(skb)) == 8))
		goto bad;

L
Linus Torvalds 已提交
216
	if (len == 0)
217
		return true;
L
Linus Torvalds 已提交
218 219
bad:
	kfree_skb(skb);
220
	return false;
L
Linus Torvalds 已提交
221 222 223 224 225 226
}

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

227
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
228
static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
229 230 231
{
	struct ipv6_destopt_hao *hao;
	struct inet6_skb_parm *opt = IP6CB(skb);
232
	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
233 234 235 236 237 238 239 240 241 242
	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;

243
	hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
244 245 246 247 248 249 250 251 252

	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 已提交
253
			KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr);
254 255 256 257 258 259 260 261 262
		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)) {
263
		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
264 265 266
			goto discard;

		/* update all variable using below by copied skbuff */
267
		hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) +
268
						  optoff);
269
		ipv6h = ipv6_hdr(skb);
270 271 272 273 274
	}

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

A
Alexey Dobriyan 已提交
275 276 277
	tmp_addr = ipv6h->saddr;
	ipv6h->saddr = hao->addr;
	hao->addr = tmp_addr;
278

279
	if (skb->tstamp.tv64 == 0)
280 281
		__net_timestamp(skb);

282
	return true;
283 284 285

 discard:
	kfree_skb(skb);
286
	return false;
287 288 289
}
#endif

290
static const struct tlvtype_proc tlvprocdestopt_lst[] = {
291
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
292 293 294 295 296
	{
		.type	= IPV6_TLV_HAO,
		.func	= ipv6_dest_hao,
	},
#endif
L
Linus Torvalds 已提交
297 298 299
	{-1,			NULL}
};

300
static int ipv6_destopt_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
301 302
{
	struct inet6_skb_parm *opt = IP6CB(skb);
303
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
304 305
	__u16 dstbuf;
#endif
306
	struct dst_entry *dst = skb_dst(skb);
L
Linus Torvalds 已提交
307

308 309
	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
310
				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
311
		IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst),
312
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
313 314 315 316
		kfree_skb(skb);
		return -1;
	}

317
	opt->lastopt = opt->dst1 = skb_network_header_len(skb);
318
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
319 320
	dstbuf = opt->dst1;
#endif
L
Linus Torvalds 已提交
321

322
	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
323
		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
324
		opt = IP6CB(skb);
325
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
326 327
		opt->nhoff = dstbuf;
#else
328
		opt->nhoff = opt->dst1;
329
#endif
L
Linus Torvalds 已提交
330 331 332
		return 1;
	}

333 334
	IP6_INC_STATS_BH(dev_net(dst->dev),
			 ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
335 336 337 338 339 340 341
	return -1;
}

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

342
/* called with rcu_read_lock() */
343
static int ipv6_rthdr_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
344 345
{
	struct inet6_skb_parm *opt = IP6CB(skb);
346
	struct in6_addr *addr = NULL;
L
Linus Torvalds 已提交
347
	struct in6_addr daddr;
348
	struct inet6_dev *idev;
L
Linus Torvalds 已提交
349 350 351
	int n, i;
	struct ipv6_rt_hdr *hdr;
	struct rt0_hdr *rthdr;
352 353
	struct net *net = dev_net(skb->dev);
	int accept_source_route = net->ipv6.devconf_all->accept_source_route;
354

355 356 357
	idev = __in6_dev_get(skb->dev);
	if (idev && accept_source_route > idev->cnf.accept_source_route)
		accept_source_route = idev->cnf.accept_source_route;
358

359 360
	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
361
				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
E
Eric Dumazet 已提交
362
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
363
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
364 365 366 367
		kfree_skb(skb);
		return -1;
	}

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

370
	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
L
Linus Torvalds 已提交
371
	    skb->pkt_type != PACKET_HOST) {
E
Eric Dumazet 已提交
372
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
373
				 IPSTATS_MIB_INADDRERRORS);
L
Linus Torvalds 已提交
374 375 376 377 378 379
		kfree_skb(skb);
		return -1;
	}

looped_back:
	if (hdr->segments_left == 0) {
380
		switch (hdr->type) {
381
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
382 383 384 385 386
		case IPV6_SRCRT_TYPE_2:
			/* Silently discard type 2 header unless it was
			 * processed by own
			 */
			if (!addr) {
E
Eric Dumazet 已提交
387
				IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
388
						 IPSTATS_MIB_INADDRERRORS);
389 390 391 392 393 394 395 396 397
				kfree_skb(skb);
				return -1;
			}
			break;
#endif
		default:
			break;
		}

398
		opt->lastopt = opt->srcrt = skb_network_header_len(skb);
399
		skb->transport_header += (hdr->hdrlen + 1) << 3;
L
Linus Torvalds 已提交
400 401
		opt->dst0 = opt->dst1;
		opt->dst1 = 0;
402
		opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
L
Linus Torvalds 已提交
403 404 405
		return 1;
	}

406
	switch (hdr->type) {
407
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
408
	case IPV6_SRCRT_TYPE_2:
409 410
		if (accept_source_route < 0)
			goto unknown_rh;
411 412
		/* Silently discard invalid RTH type 2 */
		if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
E
Eric Dumazet 已提交
413
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
414
					 IPSTATS_MIB_INHDRERRORS);
415 416 417 418 419
			kfree_skb(skb);
			return -1;
		}
		break;
#endif
420 421
	default:
		goto unknown_rh;
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429 430 431
	}

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

	n = hdr->hdrlen >> 1;

	if (hdr->segments_left > n) {
E
Eric Dumazet 已提交
432
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
433
				 IPSTATS_MIB_INHDRERRORS);
434 435 436
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
				  ((&hdr->segments_left) -
				   skb_network_header(skb)));
L
Linus Torvalds 已提交
437 438 439 440 441 442 443 444
		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 */
445
		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
E
Eric Dumazet 已提交
446
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
447 448
					 IPSTATS_MIB_OUTDISCARDS);
			kfree_skb(skb);
L
Linus Torvalds 已提交
449 450
			return -1;
		}
451
		hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
L
Linus Torvalds 已提交
452 453
	}

454
	if (skb->ip_summed == CHECKSUM_COMPLETE)
L
Linus Torvalds 已提交
455 456 457 458 459 460 461 462
		skb->ip_summed = CHECKSUM_NONE;

	i = n - --hdr->segments_left;

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

463
	switch (hdr->type) {
464
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
465 466
	case IPV6_SRCRT_TYPE_2:
		if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
467
				     (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
468
				     IPPROTO_ROUTING) < 0) {
E
Eric Dumazet 已提交
469
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
470
					 IPSTATS_MIB_INADDRERRORS);
471 472 473
			kfree_skb(skb);
			return -1;
		}
E
Eric Dumazet 已提交
474 475
		if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
476
					 IPSTATS_MIB_INADDRERRORS);
477 478 479 480 481 482 483 484 485
			kfree_skb(skb);
			return -1;
		}
		break;
#endif
	default:
		break;
	}

L
Linus Torvalds 已提交
486
	if (ipv6_addr_is_multicast(addr)) {
E
Eric Dumazet 已提交
487
		IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
488
				 IPSTATS_MIB_INADDRERRORS);
L
Linus Torvalds 已提交
489 490 491 492
		kfree_skb(skb);
		return -1;
	}

A
Alexey Dobriyan 已提交
493 494 495
	daddr = *addr;
	*addr = ipv6_hdr(skb)->daddr;
	ipv6_hdr(skb)->daddr = daddr;
L
Linus Torvalds 已提交
496

E
Eric Dumazet 已提交
497
	skb_dst_drop(skb);
L
Linus Torvalds 已提交
498
	ip6_route_input(skb);
E
Eric Dumazet 已提交
499
	if (skb_dst(skb)->error) {
500
		skb_push(skb, skb->data - skb_network_header(skb));
L
Linus Torvalds 已提交
501 502 503 504
		dst_input(skb);
		return -1;
	}

E
Eric Dumazet 已提交
505
	if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
506
		if (ipv6_hdr(skb)->hop_limit <= 1) {
E
Eric Dumazet 已提交
507
			IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
508
					 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
509
			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
510
				    0);
L
Linus Torvalds 已提交
511 512 513
			kfree_skb(skb);
			return -1;
		}
514
		ipv6_hdr(skb)->hop_limit--;
L
Linus Torvalds 已提交
515 516 517
		goto looped_back;
	}

518
	skb_push(skb, skb->data - skb_network_header(skb));
L
Linus Torvalds 已提交
519 520
	dst_input(skb);
	return -1;
521 522

unknown_rh:
E
Eric Dumazet 已提交
523
	IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
524 525 526
	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
			  (&hdr->type) - skb_network_header(skb));
	return -1;
L
Linus Torvalds 已提交
527 528
}

529
static const struct inet6_protocol rthdr_protocol = {
L
Linus Torvalds 已提交
530
	.handler	=	ipv6_rthdr_rcv,
H
Herbert Xu 已提交
531
	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
L
Linus Torvalds 已提交
532 533
};

534
static const struct inet6_protocol destopt_protocol = {
535 536 537 538
	.handler	=	ipv6_destopt_rcv,
	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,
};

539
static const struct inet6_protocol nodata_protocol = {
540 541 542 543 544
	.handler	=	dst_discard,
	.flags		=	INET6_PROTO_NOPOLICY,
};

int __init ipv6_exthdrs_init(void)
L
Linus Torvalds 已提交
545
{
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
	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 已提交
567 568
};

569 570 571 572 573 574 575
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 已提交
576 577 578 579
/**********************************
  Hop-by-hop options.
 **********************************/

580
/*
E
Eric Dumazet 已提交
581
 * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input().
582 583 584
 */
static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
{
E
Eric Dumazet 已提交
585
	return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev);
586 587
}

588 589 590 591 592
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 已提交
593 594
/* Router Alert as of RFC 2711 */

595
static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
L
Linus Torvalds 已提交
596
{
597
	const unsigned char *nh = skb_network_header(skb);
598

599
	if (nh[optoff + 1] == 2) {
L
Linus Torvalds 已提交
600
		IP6CB(skb)->ra = optoff;
601
		return true;
L
Linus Torvalds 已提交
602
	}
603
	LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
604
		       nh[optoff + 1]);
L
Linus Torvalds 已提交
605
	kfree_skb(skb);
606
	return false;
L
Linus Torvalds 已提交
607 608 609 610
}

/* Jumbo payload */

611
static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
L
Linus Torvalds 已提交
612
{
613
	const unsigned char *nh = skb_network_header(skb);
614
	struct net *net = ipv6_skb_net(skb);
L
Linus Torvalds 已提交
615 616
	u32 pkt_len;

617
	if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
618
		LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
619
			       nh[optoff+1]);
620
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
621
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
622 623 624
		goto drop;
	}

625
	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
L
Linus Torvalds 已提交
626
	if (pkt_len <= IPV6_MAXPLEN) {
627 628
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
629
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
630
		return false;
L
Linus Torvalds 已提交
631
	}
632
	if (ipv6_hdr(skb)->payload_len) {
633 634
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
				 IPSTATS_MIB_INHDRERRORS);
L
Linus Torvalds 已提交
635
		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
636
		return false;
L
Linus Torvalds 已提交
637 638 639
	}

	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
640 641
		IP6_INC_STATS_BH(net, ipv6_skb_idev(skb),
				 IPSTATS_MIB_INTRUNCATEDPKTS);
L
Linus Torvalds 已提交
642 643
		goto drop;
	}
644 645 646 647

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

648
	return true;
L
Linus Torvalds 已提交
649 650 651

drop:
	kfree_skb(skb);
652
	return false;
L
Linus Torvalds 已提交
653 654
}

655
static const struct tlvtype_proc tlvprochopopt_lst[] = {
L
Linus Torvalds 已提交
656 657 658 659 660 661 662 663 664 665 666
	{
		.type	= IPV6_TLV_ROUTERALERT,
		.func	= ipv6_hop_ra,
	},
	{
		.type	= IPV6_TLV_JUMBO,
		.func	= ipv6_hop_jumbo,
	},
	{ -1, }
};

667
int ipv6_parse_hopopts(struct sk_buff *skb)
L
Linus Torvalds 已提交
668
{
669 670
	struct inet6_skb_parm *opt = IP6CB(skb);

671
	/*
672
	 * skb_network_header(skb) is equal to skb->data, and
673
	 * skb_network_header_len(skb) is always equal to
674 675 676 677
	 * sizeof(struct ipv6hdr) by definition of
	 * hop-by-hop options.
	 */
	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
678 679
	    !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
680 681 682 683
		kfree_skb(skb);
		return -1;
	}

684
	opt->hop = sizeof(struct ipv6hdr);
685
	if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {
686
		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
687
		opt = IP6CB(skb);
688
		opt->nhoff = sizeof(struct ipv6hdr);
689
		return 1;
690
	}
L
Linus Torvalds 已提交
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
	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;
712

L
Linus Torvalds 已提交
713 714 715 716 717 718 719 720 721
	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));

A
Alexey Dobriyan 已提交
722
	phdr->addr[hops - 1] = **addr_p;
L
Linus Torvalds 已提交
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
	*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)
{
742
	if (opt->srcrt) {
L
Linus Torvalds 已提交
743
		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
744 745 746 747 748 749 750
		/*
		 * 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 已提交
751 752 753
	if (opt->hopopt)
		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
}
754 755
EXPORT_SYMBOL(ipv6_push_nfrag_opts);

L
Linus Torvalds 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768
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) {
769
		long dif = (char *)opt2 - (char *)opt;
L
Linus Torvalds 已提交
770 771
		memcpy(opt2, opt, opt->tot_len);
		if (opt2->hopopt)
772
			*((char **)&opt2->hopopt) += dif;
L
Linus Torvalds 已提交
773
		if (opt2->dst0opt)
774
			*((char **)&opt2->dst0opt) += dif;
L
Linus Torvalds 已提交
775
		if (opt2->dst1opt)
776
			*((char **)&opt2->dst1opt) += dif;
L
Linus Torvalds 已提交
777
		if (opt2->srcrt)
778
			*((char **)&opt2->srcrt) += dif;
L
Linus Torvalds 已提交
779 780 781
	}
	return opt2;
}
782 783
EXPORT_SYMBOL_GPL(ipv6_dup_options);

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
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;

819 820 821 822 823 824 825 826 827 828 829
	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));
	}

830 831 832 833 834 835
	if (newopt && newoptlen)
		tot_len += CMSG_ALIGN(newoptlen);

	if (!tot_len)
		return NULL;

836
	tot_len += sizeof(*opt2);
837 838 839 840 841 842 843 844 845
	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);

846
	err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
847 848 849 850 851
				newtype != IPV6_HOPOPTS,
				&opt2->hopopt, &p);
	if (err)
		goto out;

852
	err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
853 854 855 856 857
				newtype != IPV6_RTHDRDSTOPTS,
				&opt2->dst0opt, &p);
	if (err)
		goto out;

858
	err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
859
				newtype != IPV6_RTHDR,
860
				(struct ipv6_opt_hdr **)&opt2->srcrt, &p);
861 862 863
	if (err)
		goto out;

864
	err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
865 866 867 868 869 870 871 872 873 874 875 876
				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:
877
	sock_kfree_s(sk, opt2, opt2->tot_len);
878 879 880
	return ERR_PTR(err);
}

881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
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;
}
899
EXPORT_SYMBOL_GPL(ipv6_fixup_options);
900

901 902 903 904
/**
 * fl6_update_dst - update flowi destination address with info given
 *                  by srcrt option, if any.
 *
905
 * @fl6: flowi6 for which daddr is to be updated
906
 * @opt: struct ipv6_txoptions in which to look for srcrt opt
907
 * @orig: copy of original daddr address if modified
908 909
 *
 * Returns NULL if no txoptions or no srcrt, otherwise returns orig
910
 * and initial value of fl6->daddr set in orig
911
 */
912
struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
913 914 915 916 917 918
				const struct ipv6_txoptions *opt,
				struct in6_addr *orig)
{
	if (!opt || !opt->srcrt)
		return NULL;

A
Alexey Dobriyan 已提交
919 920
	*orig = fl6->daddr;
	fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr;
921 922 923
	return orig;
}
EXPORT_SYMBOL_GPL(fl6_update_dst);