Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef449678 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tcp_fast_open_synack_fin'



Eric Dumazet says:

====================
tcp: fastopen: accept data/FIN present in SYNACK

Implements RFC 7413 (TCP Fast Open) 4.2.2, accepting payload and/or FIN
in SYNACK messages, and prepare removal of SYN flag in tcp_recvmsg()
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents df03288b 9d691539
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1437,6 +1437,7 @@ void tcp_free_fastopen_req(struct tcp_sock *tp);

extern struct tcp_fastopen_context __rcu *tcp_fastopen_ctx;
int tcp_fastopen_reset_cipher(void *key, unsigned int len);
void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb);
struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb,
			      struct request_sock *req,
			      struct tcp_fastopen_cookie *foc,
+6 −2
Original line number Diff line number Diff line
@@ -1466,8 +1466,10 @@ static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)

	while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
		offset = seq - TCP_SKB_CB(skb)->seq;
		if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
		if (unlikely(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) {
			pr_err_once("%s: found a SYN, please report !\n", __func__);
			offset--;
		}
		if (offset < skb->len || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) {
			*off = offset;
			return skb;
@@ -1657,8 +1659,10 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
				break;

			offset = *seq - TCP_SKB_CB(skb)->seq;
			if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
			if (unlikely(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) {
				pr_err_once("%s: found a SYN, please report !\n", __func__);
				offset--;
			}
			if (offset < skb->len)
				goto found_ok_skb;
			if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
+37 −30
Original line number Diff line number Diff line
@@ -124,6 +124,38 @@ static bool tcp_fastopen_cookie_gen(struct request_sock *req,
	return false;
}


/* If an incoming SYN or SYNACK frame contains a payload and/or FIN,
 * queue this additional data / FIN.
 */
void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb)
{
	struct tcp_sock *tp = tcp_sk(sk);

	if (TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt)
		return;

	skb = skb_clone(skb, GFP_ATOMIC);
	if (!skb)
		return;

	skb_dst_drop(skb);
	__skb_pull(skb, tcp_hdrlen(skb));
	skb_set_owner_r(skb, sk);

	TCP_SKB_CB(skb)->seq++;
	TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_SYN;

	tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
	__skb_queue_tail(&sk->sk_receive_queue, skb);
	tp->syn_data_acked = 1;

	/* u64_stats_update_begin(&tp->syncp) not needed here,
	 * as we certainly are not changing upper 32bit value (0)
	 */
	tp->bytes_received = skb->len;
}

static struct sock *tcp_fastopen_create_child(struct sock *sk,
					      struct sk_buff *skb,
					      struct dst_entry *dst,
@@ -132,7 +164,6 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
	struct tcp_sock *tp;
	struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
	struct sock *child;
	u32 end_seq;
	bool own_req;

	req->num_retrans = 0;
@@ -178,35 +209,11 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
	tcp_init_metrics(child);
	tcp_init_buffer_space(child);

	/* Queue the data carried in the SYN packet.
	 * We used to play tricky games with skb_get().
	 * With lockless listener, it is a dead end.
	 * Do not think about it.
	 *
	 * XXX (TFO) - we honor a zero-payload TFO request for now,
	 * (any reason not to?) but no need to queue the skb since
	 * there is no data. How about SYN+FIN?
	 */
	end_seq = TCP_SKB_CB(skb)->end_seq;
	if (end_seq != TCP_SKB_CB(skb)->seq + 1) {
		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);

		if (likely(skb2)) {
			skb_dst_drop(skb2);
			__skb_pull(skb2, tcp_hdrlen(skb));
			skb_set_owner_r(skb2, child);
			__skb_queue_tail(&child->sk_receive_queue, skb2);
			tp->syn_data_acked = 1;
	tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;

			/* u64_stats_update_begin(&tp->syncp) not needed here,
			 * as we certainly are not changing upper 32bit value (0)
			 */
			tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1;
		} else {
			end_seq = TCP_SKB_CB(skb)->seq + 1;
		}
	}
	tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = end_seq;
	tcp_fastopen_add_skb(child, skb);

	tcp_rsk(req)->rcv_nxt = tp->rcv_nxt;
	/* tcp_conn_request() is sending the SYNACK,
	 * and queues the child into listener accept queue.
	 */
+3 −0
Original line number Diff line number Diff line
@@ -5509,6 +5509,9 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
	tp->syn_data_acked = tp->syn_data;
	if (tp->syn_data_acked)
		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE);

	tcp_fastopen_add_skb(sk, synack);

	return false;
}