tcp_ipv6.c 52.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2
/*
 *	TCP over IPv6
3
 *	Linux INET6 implementation
Linus Torvalds's avatar
Linus Torvalds committed
4 5
 *
 *	Authors:
6
 *	Pedro Roque		<roque@di.fc.ul.pt>
Linus Torvalds's avatar
Linus Torvalds committed
7
 *
8
 *	Based on:
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *	linux/net/ipv4/tcp.c
 *	linux/net/ipv4/tcp_input.c
 *	linux/net/ipv4/tcp_output.c
 *
 *	Fixes:
 *	Hideaki YOSHIFUJI	:	sin6_scope_id support
 *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
 *	Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
 *					a single port at the same time.
 *	YOSHIFUJI Hideaki @USAGI:	convert /proc/net/tcp6 to seq_file.
 *
 *	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.
 */

26
#include <linux/bottom_half.h>
Linus Torvalds's avatar
Linus Torvalds committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/jiffies.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/jhash.h>
#include <linux/ipsec.h>
#include <linux/times.h>
41
#include <linux/slab.h>
42
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
43 44 45 46 47 48
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/random.h>

#include <net/tcp.h>
#include <net/ndisc.h>
49
#include <net/inet6_hashtables.h>
50
#include <net/inet6_connection_sock.h>
Linus Torvalds's avatar
Linus Torvalds committed
51 52 53 54 55 56 57 58 59 60
#include <net/ipv6.h>
#include <net/transp_v6.h>
#include <net/addrconf.h>
#include <net/ip6_route.h>
#include <net/ip6_checksum.h>
#include <net/inet_ecn.h>
#include <net/protocol.h>
#include <net/xfrm.h>
#include <net/snmp.h>
#include <net/dsfield.h>
61
#include <net/timewait_sock.h>
62
#include <net/inet_common.h>
63
#include <net/secure_seq.h>
64
#include <net/busy_poll.h>
Linus Torvalds's avatar
Linus Torvalds committed
65 66 67 68

#include <linux/proc_fs.h>
#include <linux/seq_file.h>

Herbert Xu's avatar
Herbert Xu committed
69
#include <crypto/hash.h>
70 71
#include <linux/scatterlist.h>

72 73
#include <trace/events/tcp.h>

74 75
static void	tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb);
static void	tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
76
				      struct request_sock *req);
Linus Torvalds's avatar
Linus Torvalds committed
77 78 79

static int	tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);

80 81
static const struct inet_connection_sock_af_ops ipv6_mapped;
static const struct inet_connection_sock_af_ops ipv6_specific;
82
#ifdef CONFIG_TCP_MD5SIG
83 84
static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
85
#else
86
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk,
87
						   const struct in6_addr *addr)
88 89 90
{
	return NULL;
}
91
#endif
Linus Torvalds's avatar
Linus Torvalds committed
92

93 94 95 96
static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
	struct dst_entry *dst = skb_dst(skb);

97
	if (dst && dst_hold_safe(dst)) {
98 99 100 101
		const struct rt6_info *rt = (const struct rt6_info *)dst;

		sk->sk_rx_dst = dst;
		inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
102
		inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt);
103
	}
104 105
}

106
static u32 tcp_v6_init_seq(const struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
107
{
108 109 110 111 112 113
	return secure_tcpv6_seq(ipv6_hdr(skb)->daddr.s6_addr32,
				ipv6_hdr(skb)->saddr.s6_addr32,
				tcp_hdr(skb)->dest,
				tcp_hdr(skb)->source);
}

114
static u32 tcp_v6_init_ts_off(const struct net *net, const struct sk_buff *skb)
115
{
116
	return secure_tcpv6_ts_off(net, ipv6_hdr(skb)->daddr.s6_addr32,
117
				   ipv6_hdr(skb)->saddr.s6_addr32);
Linus Torvalds's avatar
Linus Torvalds committed
118 119
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static int tcp_v6_pre_connect(struct sock *sk, struct sockaddr *uaddr,
			      int addr_len)
{
	/* This check is replicated from tcp_v6_connect() and intended to
	 * prevent BPF program called below from accessing bytes that are out
	 * of the bound specified by user in addr_len.
	 */
	if (addr_len < SIN6_LEN_RFC2133)
		return -EINVAL;

	sock_owned_by_me(sk);

	return BPF_CGROUP_RUN_PROG_INET6_CONNECT(sk, uaddr);
}

135
static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds's avatar
Linus Torvalds committed
136 137 138
			  int addr_len)
{
	struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
139
	struct inet_sock *inet = inet_sk(sk);
140
	struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds's avatar
Linus Torvalds committed
141 142
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct tcp_sock *tp = tcp_sk(sk);
143
	struct in6_addr *saddr = NULL, *final_p, final;
144
	struct ipv6_txoptions *opt;
145
	struct flowi6 fl6;
Linus Torvalds's avatar
Linus Torvalds committed
146 147 148
	struct dst_entry *dst;
	int addr_type;
	int err;
149
	struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
Linus Torvalds's avatar
Linus Torvalds committed
150

151
	if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds's avatar
Linus Torvalds committed
152 153
		return -EINVAL;

154
	if (usin->sin6_family != AF_INET6)
155
		return -EAFNOSUPPORT;
Linus Torvalds's avatar
Linus Torvalds committed
156

157
	memset(&fl6, 0, sizeof(fl6));
Linus Torvalds's avatar
Linus Torvalds committed
158 159

	if (np->sndflow) {
160 161 162
		fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
		IP6_ECN_flow_init(fl6.flowlabel);
		if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
Linus Torvalds's avatar
Linus Torvalds committed
163
			struct ip6_flowlabel *flowlabel;
164
			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
165
			if (!flowlabel)
Linus Torvalds's avatar
Linus Torvalds committed
166 167 168 169 170 171
				return -EINVAL;
			fl6_sock_release(flowlabel);
		}
	}

	/*
172 173 174
	 *	connect() to INADDR_ANY means loopback (BSD'ism).
	 */

175 176 177 178 179 180 181
	if (ipv6_addr_any(&usin->sin6_addr)) {
		if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr))
			ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK),
					       &usin->sin6_addr);
		else
			usin->sin6_addr = in6addr_loopback;
	}
Linus Torvalds's avatar
Linus Torvalds committed
182 183 184

	addr_type = ipv6_addr_type(&usin->sin6_addr);

185
	if (addr_type & IPV6_ADDR_MULTICAST)
Linus Torvalds's avatar
Linus Torvalds committed
186 187 188 189 190 191 192 193
		return -ENETUNREACH;

	if (addr_type&IPV6_ADDR_LINKLOCAL) {
		if (addr_len >= sizeof(struct sockaddr_in6) &&
		    usin->sin6_scope_id) {
			/* If interface is set while binding, indices
			 * must coincide.
			 */
194
			if (!sk_dev_equal_l3scope(sk, usin->sin6_scope_id))
Linus Torvalds's avatar
Linus Torvalds committed
195 196 197 198 199 200 201 202 203 204 205
				return -EINVAL;

			sk->sk_bound_dev_if = usin->sin6_scope_id;
		}

		/* Connect to link-local address requires an interface */
		if (!sk->sk_bound_dev_if)
			return -EINVAL;
	}

	if (tp->rx_opt.ts_recent_stamp &&
206
	    !ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) {
Linus Torvalds's avatar
Linus Torvalds committed
207 208 209 210 211
		tp->rx_opt.ts_recent = 0;
		tp->rx_opt.ts_recent_stamp = 0;
		tp->write_seq = 0;
	}

212
	sk->sk_v6_daddr = usin->sin6_addr;
213
	np->flow_label = fl6.flowlabel;
Linus Torvalds's avatar
Linus Torvalds committed
214 215 216 217 218

	/*
	 *	TCP over IPv4
	 */

219
	if (addr_type & IPV6_ADDR_MAPPED) {
220
		u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds's avatar
Linus Torvalds committed
221 222 223 224 225 226 227 228 229 230 231
		struct sockaddr_in sin;

		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");

		if (__ipv6_only_sock(sk))
			return -ENETUNREACH;

		sin.sin_family = AF_INET;
		sin.sin_port = usin->sin6_port;
		sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];

232
		icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds's avatar
Linus Torvalds committed
233
		sk->sk_backlog_rcv = tcp_v4_do_rcv;
234 235 236
#ifdef CONFIG_TCP_MD5SIG
		tp->af_specific = &tcp_sock_ipv6_mapped_specific;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
237 238 239 240

		err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));

		if (err) {
241 242
			icsk->icsk_ext_hdr_len = exthdrlen;
			icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds's avatar
Linus Torvalds committed
243
			sk->sk_backlog_rcv = tcp_v6_do_rcv;
244 245 246
#ifdef CONFIG_TCP_MD5SIG
			tp->af_specific = &tcp_sock_ipv6_specific;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
247 248
			goto failure;
		}
249
		np->saddr = sk->sk_v6_rcv_saddr;
Linus Torvalds's avatar
Linus Torvalds committed
250 251 252 253

		return err;
	}

254 255
	if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr))
		saddr = &sk->sk_v6_rcv_saddr;
Linus Torvalds's avatar
Linus Torvalds committed
256

257
	fl6.flowi6_proto = IPPROTO_TCP;
258
	fl6.daddr = sk->sk_v6_daddr;
259
	fl6.saddr = saddr ? *saddr : np->saddr;
260 261
	fl6.flowi6_oif = sk->sk_bound_dev_if;
	fl6.flowi6_mark = sk->sk_mark;
262 263
	fl6.fl6_dport = usin->sin6_port;
	fl6.fl6_sport = inet->inet_sport;
264
	fl6.flowi6_uid = sk->sk_uid;
Linus Torvalds's avatar
Linus Torvalds committed
265

266
	opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
267
	final_p = fl6_update_dst(&fl6, opt, &final);
Linus Torvalds's avatar
Linus Torvalds committed
268

269
	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
270

271
	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
272 273
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
Linus Torvalds's avatar
Linus Torvalds committed
274
		goto failure;
275
	}
Linus Torvalds's avatar
Linus Torvalds committed
276

277
	if (!saddr) {
278
		saddr = &fl6.saddr;
279
		sk->sk_v6_rcv_saddr = *saddr;
Linus Torvalds's avatar
Linus Torvalds committed
280 281 282
	}

	/* set the source address */
283
	np->saddr = *saddr;
284
	inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds's avatar
Linus Torvalds committed
285

286
	sk->sk_gso_type = SKB_GSO_TCPV6;
Eric Dumazet's avatar
Eric Dumazet committed
287
	ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
288

289
	icsk->icsk_ext_hdr_len = 0;
290 291 292
	if (opt)
		icsk->icsk_ext_hdr_len = opt->opt_flen +
					 opt->opt_nflen;
Linus Torvalds's avatar
Linus Torvalds committed
293 294 295

	tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);

296
	inet->inet_dport = usin->sin6_port;
Linus Torvalds's avatar
Linus Torvalds committed
297 298

	tcp_set_state(sk, TCP_SYN_SENT);
299
	err = inet6_hash_connect(tcp_death_row, sk);
Linus Torvalds's avatar
Linus Torvalds committed
300 301 302
	if (err)
		goto late_failure;

303
	sk_set_txhash(sk);
304

305 306
	if (likely(!tp->repair)) {
		if (!tp->write_seq)
307 308 309 310
			tp->write_seq = secure_tcpv6_seq(np->saddr.s6_addr32,
							 sk->sk_v6_daddr.s6_addr32,
							 inet->inet_sport,
							 inet->inet_dport);
311 312
		tp->tsoffset = secure_tcpv6_ts_off(sock_net(sk),
						   np->saddr.s6_addr32,
313
						   sk->sk_v6_daddr.s6_addr32);
314
	}
Linus Torvalds's avatar
Linus Torvalds committed
315

316 317 318 319 320
	if (tcp_fastopen_defer_connect(sk, &err))
		return err;
	if (err)
		goto late_failure;

Linus Torvalds's avatar
Linus Torvalds committed
321 322 323 324 325 326 327 328 329
	err = tcp_connect(sk);
	if (err)
		goto late_failure;

	return 0;

late_failure:
	tcp_set_state(sk, TCP_CLOSE);
failure:
330
	inet->inet_dport = 0;
Linus Torvalds's avatar
Linus Torvalds committed
331 332 333 334
	sk->sk_route_caps = 0;
	return err;
}

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
static void tcp_v6_mtu_reduced(struct sock *sk)
{
	struct dst_entry *dst;

	if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
		return;

	dst = inet6_csk_update_pmtu(sk, tcp_sk(sk)->mtu_info);
	if (!dst)
		return;

	if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
		tcp_sync_mss(sk, dst_mtu(dst));
		tcp_simple_retransmit(sk);
	}
}

352
static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
353
		u8 type, u8 code, int offset, __be32 info)
Linus Torvalds's avatar
Linus Torvalds committed
354
{
355
	const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
356
	const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
357 358
	struct net *net = dev_net(skb->dev);
	struct request_sock *fastopen;
Linus Torvalds's avatar
Linus Torvalds committed
359
	struct ipv6_pinfo *np;
360
	struct tcp_sock *tp;
361
	__u32 seq, snd_una;
362
	struct sock *sk;
363
	bool fatal;
364
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
365

366 367 368
	sk = __inet6_lookup_established(net, &tcp_hashinfo,
					&hdr->daddr, th->dest,
					&hdr->saddr, ntohs(th->source),
369
					skb->dev->ifindex, inet6_sdif(skb));
Linus Torvalds's avatar
Linus Torvalds committed
370

371
	if (!sk) {
372 373
		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
				  ICMP6_MIB_INERRORS);
374
		return -ENOENT;
Linus Torvalds's avatar
Linus Torvalds committed
375 376 377
	}

	if (sk->sk_state == TCP_TIME_WAIT) {
378
		inet_twsk_put(inet_twsk(sk));
379
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
380
	}
381
	seq = ntohl(th->seq);
382
	fatal = icmpv6_err_convert(type, code, &err);
383 384 385 386
	if (sk->sk_state == TCP_NEW_SYN_RECV) {
		tcp_req_err(sk, seq, fatal);
		return 0;
	}
Linus Torvalds's avatar
Linus Torvalds committed
387 388

	bh_lock_sock(sk);
389
	if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG)
390
		__NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds's avatar
Linus Torvalds committed
391 392 393 394

	if (sk->sk_state == TCP_CLOSE)
		goto out;

395
	if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
396
		__NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP);
397 398 399
		goto out;
	}

Linus Torvalds's avatar
Linus Torvalds committed
400
	tp = tcp_sk(sk);
401 402 403
	/* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
	fastopen = tp->fastopen_rsk;
	snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;
Linus Torvalds's avatar
Linus Torvalds committed
404
	if (sk->sk_state != TCP_LISTEN &&
405
	    !between(seq, snd_una, tp->snd_nxt)) {
406
		__NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds's avatar
Linus Torvalds committed
407 408 409 410 411
		goto out;
	}

	np = inet6_sk(sk);

412
	if (type == NDISC_REDIRECT) {
413 414
		if (!sock_owned_by_user(sk)) {
			struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
415

416 417 418
			if (dst)
				dst->ops->redirect(dst, sk, skb);
		}
419
		goto out;
420 421
	}

Linus Torvalds's avatar
Linus Torvalds committed
422
	if (type == ICMPV6_PKT_TOOBIG) {
423 424 425 426 427 428 429
		/* We are not interested in TCP_LISTEN and open_requests
		 * (SYN-ACKs send out by Linux are always <576bytes so
		 * they should go through unfragmented).
		 */
		if (sk->sk_state == TCP_LISTEN)
			goto out;

430 431 432
		if (!ip6_sk_accept_pmtu(sk))
			goto out;

433 434 435
		tp->mtu_info = ntohl(info);
		if (!sock_owned_by_user(sk))
			tcp_v6_mtu_reduced(sk);
436
		else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED,
437
					   &sk->sk_tsq_flags))
438
			sock_hold(sk);
Linus Torvalds's avatar
Linus Torvalds committed
439 440 441 442
		goto out;
	}


443
	/* Might be for an request_sock */
Linus Torvalds's avatar
Linus Torvalds committed
444 445
	switch (sk->sk_state) {
	case TCP_SYN_SENT:
446 447 448 449
	case TCP_SYN_RECV:
		/* Only in fast or simultaneous open. If a fast open socket is
		 * is already accepted it is treated as a connected one below.
		 */
450
		if (fastopen && !fastopen->sk)
451 452
			break;

Linus Torvalds's avatar
Linus Torvalds committed
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
		if (!sock_owned_by_user(sk)) {
			sk->sk_err = err;
			sk->sk_error_report(sk);		/* Wake people up to see the error (see connect in sock.c) */

			tcp_done(sk);
		} else
			sk->sk_err_soft = err;
		goto out;
	}

	if (!sock_owned_by_user(sk) && np->recverr) {
		sk->sk_err = err;
		sk->sk_error_report(sk);
	} else
		sk->sk_err_soft = err;

out:
	bh_unlock_sock(sk);
	sock_put(sk);
472
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
473 474 475
}


476
static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
477
			      struct flowi *fl,
478
			      struct request_sock *req,
479
			      struct tcp_fastopen_cookie *foc,
480
			      enum tcp_synack_type synack_type)
Linus Torvalds's avatar
Linus Torvalds committed
481
{
482
	struct inet_request_sock *ireq = inet_rsk(req);
Linus Torvalds's avatar
Linus Torvalds committed
483
	struct ipv6_pinfo *np = inet6_sk(sk);
484
	struct ipv6_txoptions *opt;
485
	struct flowi6 *fl6 = &fl->u.ip6;
486
	struct sk_buff *skb;
487
	int err = -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
488

489
	/* First, grab a route. */
490 491
	if (!dst && (dst = inet6_csk_route_req(sk, fl6, req,
					       IPPROTO_TCP)) == NULL)
492
		goto done;
493

494
	skb = tcp_make_synack(sk, dst, req, foc, synack_type);
495

Linus Torvalds's avatar
Linus Torvalds committed
496
	if (skb) {
497 498
		__tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr,
				    &ireq->ir_v6_rmt_addr);
Linus Torvalds's avatar
Linus Torvalds committed
499

500
		fl6->daddr = ireq->ir_v6_rmt_addr;
501
		if (np->repflow && ireq->pktopts)
502 503
			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));

504
		rcu_read_lock();
505 506 507
		opt = ireq->ipv6_opt;
		if (!opt)
			opt = rcu_dereference(np->opt);
508
		err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, np->tclass);
509
		rcu_read_unlock();
510
		err = net_xmit_eval(err);
Linus Torvalds's avatar
Linus Torvalds committed
511 512 513 514 515 516
	}

done:
	return err;
}

517

518
static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds's avatar
Linus Torvalds committed
519
{
520
	kfree(inet_rsk(req)->ipv6_opt);
521
	kfree_skb(inet_rsk(req)->pktopts);
Linus Torvalds's avatar
Linus Torvalds committed
522 523
}

524
#ifdef CONFIG_TCP_MD5SIG
525
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk,
526
						   const struct in6_addr *addr)
527
{
Eric Dumazet's avatar
Eric Dumazet committed
528
	return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6);
529 530
}

531
static struct tcp_md5sig_key *tcp_v6_md5_lookup(const struct sock *sk,
532
						const struct sock *addr_sk)
533
{
534
	return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr);
535 536
}

537 538
static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
				 char __user *optval, int optlen)
539 540 541
{
	struct tcp_md5sig cmd;
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
542
	u8 prefixlen;
543 544 545 546 547 548 549 550 551 552

	if (optlen < sizeof(cmd))
		return -EINVAL;

	if (copy_from_user(&cmd, optval, sizeof(cmd)))
		return -EFAULT;

	if (sin6->sin6_family != AF_INET6)
		return -EINVAL;

553 554 555 556 557 558 559 560 561 562
	if (optname == TCP_MD5SIG_EXT &&
	    cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) {
		prefixlen = cmd.tcpm_prefixlen;
		if (prefixlen > 128 || (ipv6_addr_v4mapped(&sin6->sin6_addr) &&
					prefixlen > 32))
			return -EINVAL;
	} else {
		prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128;
	}

563
	if (!cmd.tcpm_keylen) {
564
		if (ipv6_addr_v4mapped(&sin6->sin6_addr))
Eric Dumazet's avatar
Eric Dumazet committed
565
			return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
566
					      AF_INET, prefixlen);
Eric Dumazet's avatar
Eric Dumazet committed
567
		return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
568
				      AF_INET6, prefixlen);
569 570 571 572 573
	}

	if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
		return -EINVAL;

Eric Dumazet's avatar
Eric Dumazet committed
574 575
	if (ipv6_addr_v4mapped(&sin6->sin6_addr))
		return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
576
				      AF_INET, prefixlen, cmd.tcpm_key,
577
				      cmd.tcpm_keylen, GFP_KERNEL);
578

Eric Dumazet's avatar
Eric Dumazet committed
579
	return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
580 581
			      AF_INET6, prefixlen, cmd.tcpm_key,
			      cmd.tcpm_keylen, GFP_KERNEL);
582 583
}

584 585 586 587
static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
				   const struct in6_addr *daddr,
				   const struct in6_addr *saddr,
				   const struct tcphdr *th, int nbytes)
588 589
{
	struct tcp6_pseudohdr *bp;
590
	struct scatterlist sg;
591
	struct tcphdr *_th;
592

593
	bp = hp->scratch;
594
	/* 1. TCP pseudo-header (RFC2460) */
595 596
	bp->saddr = *saddr;
	bp->daddr = *daddr;
597
	bp->protocol = cpu_to_be32(IPPROTO_TCP);
598
	bp->len = cpu_to_be32(nbytes);
599

600 601 602 603 604 605 606
	_th = (struct tcphdr *)(bp + 1);
	memcpy(_th, th, sizeof(*th));
	_th->check = 0;

	sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
	ahash_request_set_crypt(hp->md5_req, &sg, NULL,
				sizeof(*bp) + sizeof(*th));
Herbert Xu's avatar
Herbert Xu committed
607
	return crypto_ahash_update(hp->md5_req);
608
}
609

610
static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
611
			       const struct in6_addr *daddr, struct in6_addr *saddr,
612
			       const struct tcphdr *th)
613 614
{
	struct tcp_md5sig_pool *hp;
Herbert Xu's avatar
Herbert Xu committed
615
	struct ahash_request *req;
616 617 618 619

	hp = tcp_get_md5sig_pool();
	if (!hp)
		goto clear_hash_noput;
Herbert Xu's avatar
Herbert Xu committed
620
	req = hp->md5_req;
621

Herbert Xu's avatar
Herbert Xu committed
622
	if (crypto_ahash_init(req))
623
		goto clear_hash;
624
	if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
625 626 627
		goto clear_hash;
	if (tcp_md5_hash_key(hp, key))
		goto clear_hash;
Herbert Xu's avatar
Herbert Xu committed
628 629
	ahash_request_set_crypt(req, NULL, md5_hash, 0);
	if (crypto_ahash_final(req))
630 631 632 633
		goto clear_hash;

	tcp_put_md5sig_pool();
	return 0;
634

635 636 637 638
clear_hash:
	tcp_put_md5sig_pool();
clear_hash_noput:
	memset(md5_hash, 0, 16);
639
	return 1;
640 641
}

642 643
static int tcp_v6_md5_hash_skb(char *md5_hash,
			       const struct tcp_md5sig_key *key,
644 645
			       const struct sock *sk,
			       const struct sk_buff *skb)
646
{
647
	const struct in6_addr *saddr, *daddr;
648
	struct tcp_md5sig_pool *hp;
Herbert Xu's avatar
Herbert Xu committed
649
	struct ahash_request *req;
650
	const struct tcphdr *th = tcp_hdr(skb);
651

652 653
	if (sk) { /* valid for establish/request sockets */
		saddr = &sk->sk_v6_rcv_saddr;
654
		daddr = &sk->sk_v6_daddr;
655
	} else {
656
		const struct ipv6hdr *ip6h = ipv6_hdr(skb);
657 658
		saddr = &ip6h->saddr;
		daddr = &ip6h->daddr;
659
	}
660 661 662 663

	hp = tcp_get_md5sig_pool();
	if (!hp)
		goto clear_hash_noput;
Herbert Xu's avatar
Herbert Xu committed
664
	req = hp->md5_req;
665

Herbert Xu's avatar
Herbert Xu committed
666
	if (crypto_ahash_init(req))
667 668
		goto clear_hash;

669
	if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len))
670 671 672 673 674
		goto clear_hash;
	if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
		goto clear_hash;
	if (tcp_md5_hash_key(hp, key))
		goto clear_hash;
Herbert Xu's avatar
Herbert Xu committed
675 676
	ahash_request_set_crypt(req, NULL, md5_hash, 0);
	if (crypto_ahash_final(req))
677 678 679 680 681 682 683 684 685 686
		goto clear_hash;

	tcp_put_md5sig_pool();
	return 0;

clear_hash:
	tcp_put_md5sig_pool();
clear_hash_noput:
	memset(md5_hash, 0, 16);
	return 1;
687 688
}

689 690 691 692
#endif

static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
				    const struct sk_buff *skb)
693
{
694
#ifdef CONFIG_TCP_MD5SIG
695
	const __u8 *hash_location = NULL;
696
	struct tcp_md5sig_key *hash_expected;
697
	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
698
	const struct tcphdr *th = tcp_hdr(skb);
699 700 701 702
	int genhash;
	u8 newhash[16];

	hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
703
	hash_location = tcp_parse_md5sig_option(th);
704

705 706
	/* We've parsed the options - do we have a hash? */
	if (!hash_expected && !hash_location)
707
		return false;
708 709

	if (hash_expected && !hash_location) {
710
		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
711
		return true;
712 713
	}

714
	if (!hash_expected && hash_location) {
715
		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
716
		return true;
717 718 719
	}

	/* check the signature */
720 721
	genhash = tcp_v6_md5_hash_skb(newhash,
				      hash_expected,
722
				      NULL, skb);
723

724
	if (genhash || memcmp(hash_location, newhash, 16) != 0) {
725
		NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
726 727 728 729
		net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n",
				     genhash ? "failed" : "mismatch",
				     &ip6h->saddr, ntohs(th->source),
				     &ip6h->daddr, ntohs(th->dest));
730
		return true;
731
	}
732
#endif
733
	return false;
734 735
}

736 737
static void tcp_v6_init_req(struct request_sock *req,
			    const struct sock *sk_listener,
738 739
			    struct sk_buff *skb)
{
740
	bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
741
	struct inet_request_sock *ireq = inet_rsk(req);
742
	const struct ipv6_pinfo *np = inet6_sk(sk_listener);
743 744 745 746 747

	ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr;
	ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;

	/* So that link locals have meaning */
748
	if ((!sk_listener->sk_bound_dev_if || l3_slave) &&
749
	    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
750
		ireq->ir_iif = tcp_v6_iif(skb);
751

752
	if (!TCP_SKB_CB(skb)->tcp_tw_isn &&
753
	    (ipv6_opt_accepted(sk_listener, skb, &TCP_SKB_CB(skb)->header.h6) ||
754
	     np->rxopt.bits.rxinfo ||
755 756
	     np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||
	     np->rxopt.bits.rxohlim || np->repflow)) {
757
		refcount_inc(&skb->users);
758 759 760 761
		ireq->pktopts = skb;
	}
}

762 763
static struct dst_entry *tcp_v6_route_req(const struct sock *sk,
					  struct flowi *fl,
764
					  const struct request_sock *req)
765
{
766
	return inet6_csk_route_req(sk, &fl->u.ip6, req, IPPROTO_TCP);
767 768
}

769
struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds's avatar
Linus Torvalds committed
770
	.family		=	AF_INET6,
771
	.obj_size	=	sizeof(struct tcp6_request_sock),
772
	.rtx_syn_ack	=	tcp_rtx_synack,
773 774
	.send_ack	=	tcp_v6_reqsk_send_ack,
	.destructor	=	tcp_v6_reqsk_destructor,
775
	.send_reset	=	tcp_v6_send_reset,
776
	.syn_ack_timeout =	tcp_syn_ack_timeout,
Linus Torvalds's avatar
Linus Torvalds committed
777 778
};

779
static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
780 781
	.mss_clamp	=	IPV6_MIN_MTU - sizeof(struct tcphdr) -
				sizeof(struct ipv6hdr),
782
#ifdef CONFIG_TCP_MD5SIG
783
	.req_md5_lookup	=	tcp_v6_md5_lookup,
784
	.calc_md5_hash	=	tcp_v6_md5_hash_skb,
785
#endif
786
	.init_req	=	tcp_v6_init_req,
787 788 789
#ifdef CONFIG_SYN_COOKIES
	.cookie_init_seq =	cookie_v6_init_sequence,
#endif
790
	.route_req	=	tcp_v6_route_req,
791 792
	.init_seq	=	tcp_v6_init_seq,
	.init_ts_off	=	tcp_v6_init_ts_off,
793
	.send_synack	=	tcp_v6_send_synack,
794
};
795

796
static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq,
797 798
				 u32 ack, u32 win, u32 tsval, u32 tsecr,
				 int oif, struct tcp_md5sig_key *key, int rst,
799
				 u8 tclass, __be32 label)
Linus Torvalds's avatar
Linus Torvalds committed
800
{
801 802
	const struct tcphdr *th = tcp_hdr(skb);
	struct tcphdr *t1;
Linus Torvalds's avatar
Linus Torvalds committed
803
	struct sk_buff *buff;
804
	struct flowi6 fl6;
805
	struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
806
	struct sock *ctl_sk = net->ipv6.tcp_sk;
807
	unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazet's avatar
Eric Dumazet committed
808
	struct dst_entry *dst;
809
	__be32 *topt;
810
	__u32 mark = 0;
Linus Torvalds's avatar
Linus Torvalds committed
811

812
	if (tsecr)
813
		tot_len += TCPOLEN_TSTAMP_ALIGNED;
814 815 816 817 818 819
#ifdef CONFIG_TCP_MD5SIG
	if (key)
		tot_len += TCPOLEN_MD5SIG_ALIGNED;
#endif

	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
Linus Torvalds's avatar
Linus Torvalds committed
820
			 GFP_ATOMIC);
821
	if (!buff)
822
		return;
Linus Torvalds's avatar
Linus Torvalds committed
823

824
	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
Linus Torvalds's avatar
Linus Torvalds committed
825

826
	t1 = skb_push(buff, tot_len);
827
	skb_reset_transport_header(buff);
Linus Torvalds's avatar
Linus Torvalds committed
828 829 830 831 832

	/* Swap the send and the receive. */
	memset(t1, 0, sizeof(*t1));
	t1->dest = th->source;
	t1->source = th->dest;
833
	t1->doff = tot_len / 4;
834 835 836 837 838
	t1->seq = htonl(seq);
	t1->ack_seq = htonl(ack);
	t1->ack = !rst || !th->ack;
	t1->rst = rst;
	t1->window = htons(win);
Linus Torvalds's avatar
Linus Torvalds committed
839

840 841
	topt = (__be32 *)(t1 + 1);

842
	if (tsecr) {
843 844
		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
845 846
		*topt++ = htonl(tsval);
		*topt++ = htonl(tsecr);
847 848
	}

849 850
#ifdef CONFIG_TCP_MD5SIG
	if (key) {
851 852 853
		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
				(TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
		tcp_v6_md5_hash_hdr((__u8 *)topt, key,
854 855
				    &ipv6_hdr(skb)->saddr,
				    &ipv6_hdr(skb)->daddr, t1);
856 857 858
	}
#endif

859
	memset(&fl6, 0, sizeof(fl6));
860 861
	fl6.daddr = ipv6_hdr(skb)->saddr;
	fl6.saddr = ipv6_hdr(skb)->daddr;
862
	fl6.flowlabel = label;
Linus Torvalds's avatar
Linus Torvalds committed
863

864 865 866
	buff->ip_summed = CHECKSUM_PARTIAL;
	buff->csum = 0;

867
	__tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr);
Linus Torvalds's avatar
Linus Torvalds committed
868

869
	fl6.flowi6_proto = IPPROTO_TCP;
870
	if (rt6_need_strict(&fl6.daddr) && !oif)
871
		fl6.flowi6_oif = tcp_v6_iif(skb);
872 873 874 875 876 877
	else {
		if (!oif && netif_index_is_l3_master(net, skb->skb_iif))
			oif = skb->skb_iif;

		fl6.flowi6_oif = oif;
	}
878

879 880 881 882
	if (sk)
		mark = (sk->sk_state == TCP_TIME_WAIT) ?
			inet_twsk(sk)->tw_mark : sk->sk_mark;
	fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark;
883 884
	fl6.fl6_dport = t1->dest;
	fl6.fl6_sport = t1->source;
885
	fl6.flowi6_uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);
886
	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds's avatar
Linus Torvalds committed
887

888 889 890 891
	/* Pass a socket to ip6_dst_lookup either it is for RST
	 * Underlying function will use this to retrieve the network
	 * namespace
	 */
892
	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
893 894
	if (!IS_ERR(dst)) {
		skb_dst_set(buff, dst);
895
		ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, tclass);
896
		TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
897
		if (rst)
898
			TCP_INC_STATS(net, TCP_MIB_OUTRSTS);
899
		return;
Linus Torvalds's avatar
Linus Torvalds committed
900 901 902 903 904
	}

	kfree_skb(buff);
}

905
static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
906
{
907
	const struct tcphdr *th = tcp_hdr(skb);
908
	u32 seq = 0, ack_seq = 0;
909
	struct tcp_md5sig_key *key = NULL;
910 911 912 913 914 915 916
#ifdef CONFIG_TCP_MD5SIG
	const __u8 *hash_location = NULL;
	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
	unsigned char newhash[16];
	int genhash;
	struct sock *sk1 = NULL;
#endif
917
	int oif = 0;
Linus Torvalds's avatar
Linus Torvalds committed
918

919
	if (th->rst)
Linus Torvalds's avatar
Linus Torvalds committed
920 921
		return;

922 923 924 925
	/* If sk not NULL, it means we did a successful lookup and incoming
	 * route had to be correct. prequeue might have dropped our dst.
	 */
	if (!sk && !ipv6_unicast_destination(skb))
926
		return;
Linus Torvalds's avatar
Linus Torvalds committed
927

928
#ifdef CONFIG_TCP_MD5SIG
929
	rcu_read_lock();
930
	hash_location = tcp_parse_md5sig_option(th);
931
	if (sk && sk_fullsock(sk)) {
932 933
		key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr);
	} else if (hash_location) {
934 935 936 937 938 939 940 941
		/*
		 * active side is lost. Try to find listening socket through
		 * source port, and then find md5 key through listening socket.
		 * we are not loose security here:
		 * Incoming packet is checked with md5 hash with finding key,
		 * no RST generated if md5 hash doesn't match.
		 */
		sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
942 943
					   &tcp_hashinfo, NULL, 0,
					   &ipv6h->saddr,
944
					   th->source, &ipv6h->daddr,
945 946
					   ntohs(th->source),
					   tcp_v6_iif_l3_slave(skb),
947
					   tcp_v6_sdif(skb));
948
		if (!sk1)
949
			goto out;
950 951 952

		key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr);
		if (!key)
953
			goto out;
954

955
		genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb);
956
		if (genhash || memcmp(hash_location, newhash, 16) != 0)
957
			goto out;
958
	}
959 960
#endif

961 962 963 964 965
	if (th->ack)
		seq = ntohl(th->ack_seq);
	else
		ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -
			  (th->doff << 2);
Linus Torvalds's avatar
Linus Torvalds committed
966

967 968
	if (sk) {
		oif = sk->sk_bound_dev_if;
969 970
		if (sk_fullsock(sk))
			trace_tcp_send_reset(sk, skb);
971 972
	}

973
	tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0);
974 975

#ifdef CONFIG_TCP_MD5SIG
976 977
out:
	rcu_read_unlock();
978
#endif
979
}
Linus Torvalds's avatar
Linus Torvalds committed
980

981
static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq,
982
			    u32 ack, u32 win, u32 tsval, u32 tsecr, int oif,
983
			    struct tcp_md5sig_key *key, u8 tclass,
984
			    __be32 label)
985
{
986 987
	tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0,
			     tclass, label);
Linus Torvalds's avatar
Linus Torvalds committed
988 989 990 991
}

static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
{
992
	struct inet_timewait_sock *tw = inet_twsk(sk);
993
	struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
Linus Torvalds's avatar
Linus Torvalds committed
994

995
	tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
996
			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
997
			tcp_time_stamp_raw() + tcptw->tw_ts_offset,
998
			tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw),
999
			tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel));
Linus Torvalds's avatar
Linus Torvalds committed
1000

1001
	inet_twsk_put(tw);
Linus Torvalds's avatar
Linus Torvalds committed
1002 1003
}

1004
static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
1005
				  struct request_sock *req)
Linus Torvalds's avatar
Linus Torvalds committed
1006
{
1007 1008 1009
	/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
	 * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
	 */
1010 1011 1012 1013 1014
	/* RFC 7323 2.3
	 * The window field (SEG.WND) of every outgoing segment, with the
	 * exception of <SYN> segments, MUST be right-shifted by
	 * Rcv.Wind.Shift bits:
	 */
1015
	tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ?
1016
			tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
1017 1018
			tcp_rsk(req)->rcv_nxt,
			req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
1019
			tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,
1020
			req->ts_recent, sk->sk_bound_dev_if,
1021
			tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr),
1022
			0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
1023 1024 1025
}


1026
static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
1027
{
1028
#ifdef CONFIG_SYN_COOKIES
1029
	const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
1030

1031
	if (!th->syn)
1032
		sk = cookie_v6_check(sk, skb);
Linus Torvalds's avatar
Linus Torvalds committed
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
#endif
	return sk;
}

static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
	if (skb->protocol == htons(ETH_P_IP))
		return tcp_v4_conn_request(sk, skb);

	if (!ipv6_unicast_destination(skb))
1043
		goto drop;
Linus Torvalds's avatar
Linus Torvalds committed
1044

1045 1046
	return tcp_conn_request(&tcp6_request_sock_ops,
				&tcp_request_sock_ipv6_ops, sk, skb);
Linus Torvalds's avatar
Linus Torvalds committed
1047 1048

drop:
1049
	tcp_listendrop(sk);
Linus Torvalds's avatar
Linus Torvalds committed
1050 1051 1052
	return 0; /* don't send reset */
}

1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
static void tcp_v6_restore_cb(struct sk_buff *skb)
{
	/* We need to move header back to the beginning if xfrm6_policy_check()
	 * and tcp_v6_fill_cb() are going to be called again.
	 * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
	 */
	memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
		sizeof(struct inet6_skb_parm));
}

1063
static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
1064
					 struct request_sock *req,
1065 1066 1067
					 struct dst_entry *dst,
					 struct request_sock *req_unhash,
					 bool *own_req)
Linus Torvalds's avatar
Linus Torvalds committed
1068
{
1069
	struct inet_request_sock *ireq;
1070 1071
	struct ipv6_pinfo *newnp;
	const struct ipv6_pinfo *np = inet6_sk(sk);
1072
	struct ipv6_txoptions *opt;