tcp_ipv6.c 51.1 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.
 */

Herbert Xu's avatar
Herbert Xu committed
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>
Linus Torvalds's avatar
Linus Torvalds committed
42 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/netdma.h>
63
#include <net/inet_common.h>
64
#include <net/secure_seq.h>
Glauber Costa's avatar
Glauber Costa committed
65
#include <net/tcp_memcontrol.h>
66
#include <net/busy_poll.h>
Linus Torvalds's avatar
Linus Torvalds committed
67 68 69 70 71 72

#include <asm/uaccess.h>

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

73 74 75 76
#include <linux/crypto.h>
#include <linux/scatterlist.h>

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

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

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

95 96 97 98 99 100 101 102 103 104 105 106
static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
	struct dst_entry *dst = skb_dst(skb);
	const struct rt6_info *rt = (const struct rt6_info *)dst;

	dst_hold(dst);
	sk->sk_rx_dst = dst;
	inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
	if (rt->rt6i_node)
		inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
}

Linus Torvalds's avatar
Linus Torvalds committed
107 108 109
static void tcp_v6_hash(struct sock *sk)
{
	if (sk->sk_state != TCP_CLOSE) {
110
		if (inet_csk(sk)->icsk_af_ops == &ipv6_mapped) {
Linus Torvalds's avatar
Linus Torvalds committed
111 112 113 114
			tcp_prot.hash(sk);
			return;
		}
		local_bh_disable();
115
		__inet6_hash(sk, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119
		local_bh_enable();
	}
}

120
static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
121
{
122 123
	return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
					    ipv6_hdr(skb)->saddr.s6_addr32,
124 125
					    tcp_hdr(skb)->dest,
					    tcp_hdr(skb)->source);
Linus Torvalds's avatar
Linus Torvalds committed
126 127
}

128
static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
Linus Torvalds's avatar
Linus Torvalds committed
129 130 131
			  int addr_len)
{
	struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
132
	struct inet_sock *inet = inet_sk(sk);
133
	struct inet_connection_sock *icsk = inet_csk(sk);
Linus Torvalds's avatar
Linus Torvalds committed
134 135
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct tcp_sock *tp = tcp_sk(sk);
136
	struct in6_addr *saddr = NULL, *final_p, final;
137
	struct rt6_info *rt;
138
	struct flowi6 fl6;
Linus Torvalds's avatar
Linus Torvalds committed
139 140 141 142
	struct dst_entry *dst;
	int addr_type;
	int err;

143
	if (addr_len < SIN6_LEN_RFC2133)
Linus Torvalds's avatar
Linus Torvalds committed
144 145
		return -EINVAL;

146
	if (usin->sin6_family != AF_INET6)
Eric Dumazet's avatar
Eric Dumazet committed
147
		return -EAFNOSUPPORT;
Linus Torvalds's avatar
Linus Torvalds committed
148

149
	memset(&fl6, 0, sizeof(fl6));
Linus Torvalds's avatar
Linus Torvalds committed
150 151

	if (np->sndflow) {
152 153 154
		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
155
			struct ip6_flowlabel *flowlabel;
156
			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
Linus Torvalds's avatar
Linus Torvalds committed
157 158
			if (flowlabel == NULL)
				return -EINVAL;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
159
			usin->sin6_addr = flowlabel->dst;
Linus Torvalds's avatar
Linus Torvalds committed
160 161 162 163 164
			fl6_sock_release(flowlabel);
		}
	}

	/*
165 166 167 168 169
	 *	connect() to INADDR_ANY means loopback (BSD'ism).
	 */

	if(ipv6_addr_any(&usin->sin6_addr))
		usin->sin6_addr.s6_addr[15] = 0x1;
Linus Torvalds's avatar
Linus Torvalds committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200

	addr_type = ipv6_addr_type(&usin->sin6_addr);

	if(addr_type & IPV6_ADDR_MULTICAST)
		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.
			 */
			if (sk->sk_bound_dev_if &&
			    sk->sk_bound_dev_if != usin->sin6_scope_id)
				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 &&
	    !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
		tp->rx_opt.ts_recent = 0;
		tp->rx_opt.ts_recent_stamp = 0;
		tp->write_seq = 0;
	}

Alexey Dobriyan's avatar
Alexey Dobriyan committed
201
	np->daddr = usin->sin6_addr;
202
	np->flow_label = fl6.flowlabel;
Linus Torvalds's avatar
Linus Torvalds committed
203 204 205 206 207 208

	/*
	 *	TCP over IPv4
	 */

	if (addr_type == IPV6_ADDR_MAPPED) {
209
		u32 exthdrlen = icsk->icsk_ext_hdr_len;
Linus Torvalds's avatar
Linus Torvalds committed
210 211 212 213 214 215 216 217 218 219 220
		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];

221
		icsk->icsk_af_ops = &ipv6_mapped;
Linus Torvalds's avatar
Linus Torvalds committed
222
		sk->sk_backlog_rcv = tcp_v4_do_rcv;
223 224 225
#ifdef CONFIG_TCP_MD5SIG
		tp->af_specific = &tcp_sock_ipv6_mapped_specific;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
226 227 228 229

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

		if (err) {
230 231
			icsk->icsk_ext_hdr_len = exthdrlen;
			icsk->icsk_af_ops = &ipv6_specific;
Linus Torvalds's avatar
Linus Torvalds committed
232
			sk->sk_backlog_rcv = tcp_v6_do_rcv;
233 234 235
#ifdef CONFIG_TCP_MD5SIG
			tp->af_specific = &tcp_sock_ipv6_specific;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
236 237
			goto failure;
		} else {
238 239 240
			ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);
			ipv6_addr_set_v4mapped(inet->inet_rcv_saddr,
					       &np->rcv_saddr);
Linus Torvalds's avatar
Linus Torvalds committed
241 242 243 244 245 246 247 248
		}

		return err;
	}

	if (!ipv6_addr_any(&np->rcv_saddr))
		saddr = &np->rcv_saddr;

249
	fl6.flowi6_proto = IPPROTO_TCP;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
250 251
	fl6.daddr = np->daddr;
	fl6.saddr = saddr ? *saddr : np->saddr;
252 253
	fl6.flowi6_oif = sk->sk_bound_dev_if;
	fl6.flowi6_mark = sk->sk_mark;
254 255
	fl6.fl6_dport = usin->sin6_port;
	fl6.fl6_sport = inet->inet_sport;
Linus Torvalds's avatar
Linus Torvalds committed
256

257
	final_p = fl6_update_dst(&fl6, np->opt, &final);
Linus Torvalds's avatar
Linus Torvalds committed
258

259
	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
260

261
	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
262 263
	if (IS_ERR(dst)) {
		err = PTR_ERR(dst);
Linus Torvalds's avatar
Linus Torvalds committed
264
		goto failure;
265
	}
Linus Torvalds's avatar
Linus Torvalds committed
266 267

	if (saddr == NULL) {
268
		saddr = &fl6.saddr;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
269
		np->rcv_saddr = *saddr;
Linus Torvalds's avatar
Linus Torvalds committed
270 271 272
	}

	/* set the source address */
Alexey Dobriyan's avatar
Alexey Dobriyan committed
273
	np->saddr = *saddr;
274
	inet->inet_rcv_saddr = LOOPBACK4_IPV6;
Linus Torvalds's avatar
Linus Torvalds committed
275

276
	sk->sk_gso_type = SKB_GSO_TCPV6;
277
	__ip6_dst_store(sk, dst, NULL, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
278

279 280 281
	rt = (struct rt6_info *) dst;
	if (tcp_death_row.sysctl_tw_recycle &&
	    !tp->rx_opt.ts_recent_stamp &&
282 283
	    ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr))
		tcp_fetch_timewait_stamp(sk, dst);
284

285
	icsk->icsk_ext_hdr_len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
286
	if (np->opt)
287 288
		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
					  np->opt->opt_nflen);
Linus Torvalds's avatar
Linus Torvalds committed
289 290 291

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

292
	inet->inet_dport = usin->sin6_port;
Linus Torvalds's avatar
Linus Torvalds committed
293 294

	tcp_set_state(sk, TCP_SYN_SENT);
295
	err = inet6_hash_connect(&tcp_death_row, sk);
Linus Torvalds's avatar
Linus Torvalds committed
296 297 298
	if (err)
		goto late_failure;

299
	if (!tp->write_seq && likely(!tp->repair))
Linus Torvalds's avatar
Linus Torvalds committed
300 301
		tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
							     np->daddr.s6_addr32,
302 303
							     inet->inet_sport,
							     inet->inet_dport);
Linus Torvalds's avatar
Linus Torvalds committed
304 305 306 307 308 309 310 311 312 313 314

	err = tcp_connect(sk);
	if (err)
		goto late_failure;

	return 0;

late_failure:
	tcp_set_state(sk, TCP_CLOSE);
	__sk_dst_reset(sk);
failure:
315
	inet->inet_dport = 0;
Linus Torvalds's avatar
Linus Torvalds committed
316 317 318 319
	sk->sk_route_caps = 0;
	return err;
}

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
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);
	}
}

Linus Torvalds's avatar
Linus Torvalds committed
337
static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
338
		u8 type, u8 code, int offset, __be32 info)
Linus Torvalds's avatar
Linus Torvalds committed
339
{
340
	const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data;
341
	const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
Linus Torvalds's avatar
Linus Torvalds committed
342 343 344
	struct ipv6_pinfo *np;
	struct sock *sk;
	int err;
345
	struct tcp_sock *tp;
Linus Torvalds's avatar
Linus Torvalds committed
346
	__u32 seq;
347
	struct net *net = dev_net(skb->dev);
Linus Torvalds's avatar
Linus Torvalds committed
348

349
	sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr,
350
			th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
Linus Torvalds's avatar
Linus Torvalds committed
351 352

	if (sk == NULL) {
353 354
		ICMP6_INC_STATS_BH(net, __in6_dev_get(skb->dev),
				   ICMP6_MIB_INERRORS);
Linus Torvalds's avatar
Linus Torvalds committed
355 356 357 358
		return;
	}

	if (sk->sk_state == TCP_TIME_WAIT) {
359
		inet_twsk_put(inet_twsk(sk));
Linus Torvalds's avatar
Linus Torvalds committed
360 361 362 363
		return;
	}

	bh_lock_sock(sk);
364
	if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG)
365
		NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
Linus Torvalds's avatar
Linus Torvalds committed
366 367 368 369

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

370 371 372 373 374
	if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
		NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
		goto out;
	}

Linus Torvalds's avatar
Linus Torvalds committed
375
	tp = tcp_sk(sk);
376
	seq = ntohl(th->seq);
Linus Torvalds's avatar
Linus Torvalds committed
377 378
	if (sk->sk_state != TCP_LISTEN &&
	    !between(seq, tp->snd_una, tp->snd_nxt)) {
379
		NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds's avatar
Linus Torvalds committed
380 381 382 383 384
		goto out;
	}

	np = inet6_sk(sk);

385 386 387
	if (type == NDISC_REDIRECT) {
		struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);

388
		if (dst)
389
			dst->ops->redirect(dst, sk, skb);
390
		goto out;
391 392
	}

Linus Torvalds's avatar
Linus Torvalds committed
393
	if (type == ICMPV6_PKT_TOOBIG) {
394 395 396 397 398 399 400
		/* 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;

401 402 403
		tp->mtu_info = ntohl(info);
		if (!sock_owned_by_user(sk))
			tcp_v6_mtu_reduced(sk);
404 405 406
		else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED,
					   &tp->tsq_flags))
			sock_hold(sk);
Linus Torvalds's avatar
Linus Torvalds committed
407 408 409 410 411
		goto out;
	}

	icmpv6_err_convert(type, code, &err);

412
	/* Might be for an request_sock */
Linus Torvalds's avatar
Linus Torvalds committed
413
	switch (sk->sk_state) {
414
		struct request_sock *req, **prev;
Linus Torvalds's avatar
Linus Torvalds committed
415 416 417 418
	case TCP_LISTEN:
		if (sock_owned_by_user(sk))
			goto out;

419 420
		req = inet6_csk_search_req(sk, &prev, th->dest, &hdr->daddr,
					   &hdr->saddr, inet6_iif(skb));
Linus Torvalds's avatar
Linus Torvalds committed
421 422 423 424 425 426
		if (!req)
			goto out;

		/* ICMPs are not backlogged, hence we cannot get
		 * an established socket here.
		 */
427
		WARN_ON(req->sk != NULL);
Linus Torvalds's avatar
Linus Torvalds committed
428

429
		if (seq != tcp_rsk(req)->snt_isn) {
430
			NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
Linus Torvalds's avatar
Linus Torvalds committed
431 432 433
			goto out;
		}

434
		inet_csk_reqsk_queue_drop(sk, req, prev);
435
		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
Linus Torvalds's avatar
Linus Torvalds committed
436 437 438 439
		goto out;

	case TCP_SYN_SENT:
	case TCP_SYN_RECV:  /* Cannot happen.
440
			       It can, it SYNs are crossed. --ANK */
Linus Torvalds's avatar
Linus Torvalds committed
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
		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);
}


463 464
static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
			      struct flowi6 *fl6,
465
			      struct request_sock *req,
466
			      u16 queue_mapping)
Linus Torvalds's avatar
Linus Torvalds committed
467
{
468
	struct inet6_request_sock *treq = inet6_rsk(req);
Linus Torvalds's avatar
Linus Torvalds committed
469 470
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct sk_buff * skb;
471
	int err = -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
472

473 474
	/* First, grab a route. */
	if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
475
		goto done;
476

Christoph Paasch's avatar
Christoph Paasch committed
477
	skb = tcp_make_synack(sk, dst, req, NULL);
478

Linus Torvalds's avatar
Linus Torvalds committed
479
	if (skb) {
480
		__tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
Linus Torvalds's avatar
Linus Torvalds committed
481

482
		fl6->daddr = treq->rmt_addr;
483
		skb_set_queue_mapping(skb, queue_mapping);
484
		err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
485
		err = net_xmit_eval(err);
Linus Torvalds's avatar
Linus Torvalds committed
486 487 488 489 490 491
	}

done:
	return err;
}

Christoph Paasch's avatar
Christoph Paasch committed
492
static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)
493
{
494
	struct flowi6 fl6;
495
	int res;
496

Christoph Paasch's avatar
Christoph Paasch committed
497
	res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0);
498 499 500
	if (!res)
		TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
	return res;
501 502
}

503
static void tcp_v6_reqsk_destructor(struct request_sock *req)
Linus Torvalds's avatar
Linus Torvalds committed
504
{
505
	kfree_skb(inet6_rsk(req)->pktopts);
Linus Torvalds's avatar
Linus Torvalds committed
506 507
}

508 509
#ifdef CONFIG_TCP_MD5SIG
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
510
						   const struct in6_addr *addr)
511
{
Eric Dumazet's avatar
Eric Dumazet committed
512
	return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6);
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
}

static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,
						struct sock *addr_sk)
{
	return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr);
}

static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,
						      struct request_sock *req)
{
	return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr);
}

static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
				  int optlen)
{
	struct tcp_md5sig cmd;
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;

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

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

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

	if (!cmd.tcpm_keylen) {
543
		if (ipv6_addr_v4mapped(&sin6->sin6_addr))
Eric Dumazet's avatar
Eric Dumazet committed
544 545 546 547
			return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
					      AF_INET);
		return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
				      AF_INET6);
548 549 550 551 552
	}

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

Eric Dumazet's avatar
Eric Dumazet committed
553 554 555
	if (ipv6_addr_v4mapped(&sin6->sin6_addr))
		return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
				      AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
556

Eric Dumazet's avatar
Eric Dumazet committed
557 558
	return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
			      AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
559 560
}

561
static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
562 563
					const struct in6_addr *daddr,
					const struct in6_addr *saddr, int nbytes)
564 565
{
	struct tcp6_pseudohdr *bp;
566
	struct scatterlist sg;
567

568 569
	bp = &hp->md5_blk.ip6;
	/* 1. TCP pseudo-header (RFC2460) */
Alexey Dobriyan's avatar
Alexey Dobriyan committed
570 571
	bp->saddr = *saddr;
	bp->daddr = *daddr;
572
	bp->protocol = cpu_to_be32(IPPROTO_TCP);
Adam Langley's avatar
Adam Langley committed
573
	bp->len = cpu_to_be32(nbytes);
574

575 576 577
	sg_init_one(&sg, bp, sizeof(*bp));
	return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
}
578

579
static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
580
			       const struct in6_addr *daddr, struct in6_addr *saddr,
581
			       const struct tcphdr *th)
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
{
	struct tcp_md5sig_pool *hp;
	struct hash_desc *desc;

	hp = tcp_get_md5sig_pool();
	if (!hp)
		goto clear_hash_noput;
	desc = &hp->md5_desc;

	if (crypto_hash_init(desc))
		goto clear_hash;
	if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
		goto clear_hash;
	if (tcp_md5_hash_header(hp, th))
		goto clear_hash;
	if (tcp_md5_hash_key(hp, key))
		goto clear_hash;
	if (crypto_hash_final(desc, md5_hash))
600 601 602 603
		goto clear_hash;

	tcp_put_md5sig_pool();
	return 0;
604

605 606 607 608
clear_hash:
	tcp_put_md5sig_pool();
clear_hash_noput:
	memset(md5_hash, 0, 16);
609
	return 1;
610 611
}

612
static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
613 614 615
			       const struct sock *sk,
			       const struct request_sock *req,
			       const struct sk_buff *skb)
616
{
617
	const struct in6_addr *saddr, *daddr;
618 619
	struct tcp_md5sig_pool *hp;
	struct hash_desc *desc;
620
	const struct tcphdr *th = tcp_hdr(skb);
621 622 623 624

	if (sk) {
		saddr = &inet6_sk(sk)->saddr;
		daddr = &inet6_sk(sk)->daddr;
625
	} else if (req) {
626 627
		saddr = &inet6_rsk(req)->loc_addr;
		daddr = &inet6_rsk(req)->rmt_addr;
628
	} else {
629
		const struct ipv6hdr *ip6h = ipv6_hdr(skb);
630 631
		saddr = &ip6h->saddr;
		daddr = &ip6h->daddr;
632
	}
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660

	hp = tcp_get_md5sig_pool();
	if (!hp)
		goto clear_hash_noput;
	desc = &hp->md5_desc;

	if (crypto_hash_init(desc))
		goto clear_hash;

	if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
		goto clear_hash;
	if (tcp_md5_hash_header(hp, th))
		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;
	if (crypto_hash_final(desc, md5_hash))
		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;
661 662
}

663
static int tcp_v6_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb)
664
{
665
	const __u8 *hash_location = NULL;
666
	struct tcp_md5sig_key *hash_expected;
667
	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
668
	const struct tcphdr *th = tcp_hdr(skb);
669 670 671 672
	int genhash;
	u8 newhash[16];

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

675 676 677 678 679 680
	/* We've parsed the options - do we have a hash? */
	if (!hash_expected && !hash_location)
		return 0;

	if (hash_expected && !hash_location) {
		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
681 682 683
		return 1;
	}

684 685
	if (!hash_expected && hash_location) {
		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED);
686 687 688 689
		return 1;
	}

	/* check the signature */
690 691 692 693
	genhash = tcp_v6_md5_hash_skb(newhash,
				      hash_expected,
				      NULL, NULL, skb);

694
	if (genhash || memcmp(hash_location, newhash, 16) != 0) {
695 696 697 698
		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));
699 700 701 702 703 704
		return 1;
	}
	return 0;
}
#endif

705
struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
Linus Torvalds's avatar
Linus Torvalds committed
706
	.family		=	AF_INET6,
707
	.obj_size	=	sizeof(struct tcp6_request_sock),
708
	.rtx_syn_ack	=	tcp_v6_rtx_synack,
709 710
	.send_ack	=	tcp_v6_reqsk_send_ack,
	.destructor	=	tcp_v6_reqsk_destructor,
711 712
	.send_reset	=	tcp_v6_send_reset,
	.syn_ack_timeout = 	tcp_syn_ack_timeout,
Linus Torvalds's avatar
Linus Torvalds committed
713 714
};

715
#ifdef CONFIG_TCP_MD5SIG
716
static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
717
	.md5_lookup	=	tcp_v6_reqsk_md5_lookup,
718
	.calc_md5_hash	=	tcp_v6_md5_hash_skb,
719
};
720
#endif
721

722
static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
723 724
				 u32 tsval, u32 tsecr,
				 struct tcp_md5sig_key *key, int rst, u8 tclass)
Linus Torvalds's avatar
Linus Torvalds committed
725
{
726 727
	const struct tcphdr *th = tcp_hdr(skb);
	struct tcphdr *t1;
Linus Torvalds's avatar
Linus Torvalds committed
728
	struct sk_buff *buff;
729
	struct flowi6 fl6;
Eric Dumazet's avatar
Eric Dumazet committed
730
	struct net *net = dev_net(skb_dst(skb)->dev);
731
	struct sock *ctl_sk = net->ipv6.tcp_sk;
732
	unsigned int tot_len = sizeof(struct tcphdr);
Eric Dumazet's avatar
Eric Dumazet committed
733
	struct dst_entry *dst;
734
	__be32 *topt;
Linus Torvalds's avatar
Linus Torvalds committed
735

736
	if (tsecr)
737
		tot_len += TCPOLEN_TSTAMP_ALIGNED;
738 739 740 741 742 743
#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
744
			 GFP_ATOMIC);
745 746
	if (buff == NULL)
		return;
Linus Torvalds's avatar
Linus Torvalds committed
747

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

750
	t1 = (struct tcphdr *) skb_push(buff, tot_len);
751
	skb_reset_transport_header(buff);
Linus Torvalds's avatar
Linus Torvalds committed
752 753 754 755 756

	/* Swap the send and the receive. */
	memset(t1, 0, sizeof(*t1));
	t1->dest = th->source;
	t1->source = th->dest;
757
	t1->doff = tot_len / 4;
758 759 760 761 762
	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
763

764 765
	topt = (__be32 *)(t1 + 1);

766
	if (tsecr) {
767 768
		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
769 770
		*topt++ = htonl(tsval);
		*topt++ = htonl(tsecr);
771 772
	}

773 774
#ifdef CONFIG_TCP_MD5SIG
	if (key) {
775 776 777
		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
				(TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
		tcp_v6_md5_hash_hdr((__u8 *)topt, key,
778 779
				    &ipv6_hdr(skb)->saddr,
				    &ipv6_hdr(skb)->daddr, t1);
780 781 782
	}
#endif

783
	memset(&fl6, 0, sizeof(fl6));
Alexey Dobriyan's avatar
Alexey Dobriyan committed
784 785
	fl6.daddr = ipv6_hdr(skb)->saddr;
	fl6.saddr = ipv6_hdr(skb)->daddr;
Linus Torvalds's avatar
Linus Torvalds committed
786

787 788 789
	buff->ip_summed = CHECKSUM_PARTIAL;
	buff->csum = 0;

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

792
	fl6.flowi6_proto = IPPROTO_TCP;
Alexey Kuznetsov's avatar
Alexey Kuznetsov committed
793 794
	if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
		fl6.flowi6_oif = inet6_iif(skb);
795 796
	fl6.fl6_dport = t1->dest;
	fl6.fl6_sport = t1->source;
797
	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
Linus Torvalds's avatar
Linus Torvalds committed
798

799 800 801 802
	/* Pass a socket to ip6_dst_lookup either it is for RST
	 * Underlying function will use this to retrieve the network
	 * namespace
	 */
803
	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false);
804 805
	if (!IS_ERR(dst)) {
		skb_dst_set(buff, dst);
806
		ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
807 808 809 810
		TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
		if (rst)
			TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
		return;
Linus Torvalds's avatar
Linus Torvalds committed
811 812 813 814 815
	}

	kfree_skb(buff);
}

816
static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
817
{
818
	const struct tcphdr *th = tcp_hdr(skb);
819
	u32 seq = 0, ack_seq = 0;
820
	struct tcp_md5sig_key *key = NULL;
821 822 823 824 825 826 827
#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
Linus Torvalds's avatar
Linus Torvalds committed
828

829
	if (th->rst)
Linus Torvalds's avatar
Linus Torvalds committed
830 831
		return;

832 833
	if (!ipv6_unicast_destination(skb))
		return;
Linus Torvalds's avatar
Linus Torvalds committed
834

835
#ifdef CONFIG_TCP_MD5SIG
836 837 838 839 840 841 842 843 844 845
	hash_location = tcp_parse_md5sig_option(th);
	if (!sk && hash_location) {
		/*
		 * 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),
846 847
					   &tcp_hashinfo, &ipv6h->saddr,
					   th->source, &ipv6h->daddr,
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
					   ntohs(th->source), inet6_iif(skb));
		if (!sk1)
			return;

		rcu_read_lock();
		key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr);
		if (!key)
			goto release_sk1;

		genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb);
		if (genhash || memcmp(hash_location, newhash, 16) != 0)
			goto release_sk1;
	} else {
		key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL;
	}
863 864
#endif

865 866 867 868 869
	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
870

871
	tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0);
872 873 874 875 876 877 878 879

#ifdef CONFIG_TCP_MD5SIG
release_sk1:
	if (sk1) {
		rcu_read_unlock();
		sock_put(sk1);
	}
#endif
880
}
Linus Torvalds's avatar
Linus Torvalds committed
881

882 883
static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
			    u32 win, u32 tsval, u32 tsecr,
884
			    struct tcp_md5sig_key *key, u8 tclass)
885
{
886
	tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass);
Linus Torvalds's avatar
Linus Torvalds committed
887 888 889 890
}

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

894
	tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
895
			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
896
			tcp_time_stamp + tcptw->tw_ts_offset,
897 898
			tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw),
			tw->tw_tclass);
Linus Torvalds's avatar
Linus Torvalds committed
899

900
	inet_twsk_put(tw);
Linus Torvalds's avatar
Linus Torvalds committed
901 902
}

903 904
static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
				  struct request_sock *req)
Linus Torvalds's avatar
Linus Torvalds committed
905
{
906 907
	tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1,
			req->rcv_wnd, tcp_time_stamp, req->ts_recent,
908
			tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
Linus Torvalds's avatar
Linus Torvalds committed
909 910 911 912 913
}


static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
{
914
	struct request_sock *req, **prev;
915
	const struct tcphdr *th = tcp_hdr(skb);
Linus Torvalds's avatar
Linus Torvalds committed
916 917 918
	struct sock *nsk;

	/* Find possible connection requests. */
919
	req = inet6_csk_search_req(sk, &prev, th->source,
920 921
				   &ipv6_hdr(skb)->saddr,
				   &ipv6_hdr(skb)->daddr, inet6_iif(skb));
Linus Torvalds's avatar
Linus Torvalds committed
922
	if (req)
923
		return tcp_check_req(sk, skb, req, prev, false);
Linus Torvalds's avatar
Linus Torvalds committed
924

925
	nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
926 927
			&ipv6_hdr(skb)->saddr, th->source,
			&ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
Linus Torvalds's avatar
Linus Torvalds committed
928 929 930 931 932 933

	if (nsk) {
		if (nsk->sk_state != TCP_TIME_WAIT) {
			bh_lock_sock(nsk);
			return nsk;
		}
934
		inet_twsk_put(inet_twsk(nsk));
Linus Torvalds's avatar
Linus Torvalds committed
935 936 937
		return NULL;
	}

938
#ifdef CONFIG_SYN_COOKIES
939
	if (!th->syn)
940
		sk = cookie_v6_check(sk, skb);
Linus Torvalds's avatar
Linus Torvalds committed
941 942 943 944 945 946 947 948 949
#endif
	return sk;
}

/* FIXME: this is substantially similar to the ipv4 code.
 * Can some kind of merge be done? -- erics
 */
static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
950 951
	struct tcp_options_received tmp_opt;
	struct request_sock *req;
952
	struct inet6_request_sock *treq;
Linus Torvalds's avatar
Linus Torvalds committed
953 954
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct tcp_sock *tp = tcp_sk(sk);
955
	__u32 isn = TCP_SKB_CB(skb)->when;
956
	struct dst_entry *dst = NULL;
957
	struct flowi6 fl6;
Eric Dumazet's avatar
Eric Dumazet committed
958
	bool want_cookie = false;
Linus Torvalds's avatar
Linus Torvalds committed
959 960 961 962 963

	if (skb->protocol == htons(ETH_P_IP))
		return tcp_v4_conn_request(sk, skb);

	if (!ipv6_unicast_destination(skb))
964
		goto drop;
Linus Torvalds's avatar
Linus Torvalds committed
965

966 967
	if ((sysctl_tcp_syncookies == 2 ||
	     inet_csk_reqsk_queue_is_full(sk)) && !isn) {
968 969 970
		want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
		if (!want_cookie)
			goto drop;
Linus Torvalds's avatar
Linus Torvalds committed
971 972
	}

973 974
	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
Linus Torvalds's avatar
Linus Torvalds committed
975
		goto drop;
976
	}