|
@@ -472,7 +472,8 @@ out:
|
|
|
static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
|
|
|
struct flowi6 *fl6,
|
|
|
struct request_sock *req,
|
|
|
- u16 queue_mapping)
|
|
|
+ u16 queue_mapping,
|
|
|
+ struct tcp_fastopen_cookie *foc)
|
|
|
{
|
|
|
struct inet_request_sock *ireq = inet_rsk(req);
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
@@ -483,7 +484,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
|
|
|
if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
|
|
|
goto done;
|
|
|
|
|
|
- skb = tcp_make_synack(sk, dst, req, NULL);
|
|
|
+ skb = tcp_make_synack(sk, dst, req, foc);
|
|
|
|
|
|
if (skb) {
|
|
|
__tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr,
|
|
@@ -507,7 +508,7 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)
|
|
|
struct flowi6 fl6;
|
|
|
int res;
|
|
|
|
|
|
- res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0);
|
|
|
+ res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0, NULL);
|
|
|
if (!res) {
|
|
|
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
|
|
|
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
|
|
@@ -926,7 +927,12 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
|
|
|
static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
|
|
|
struct request_sock *req)
|
|
|
{
|
|
|
- tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1,
|
|
|
+ /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
|
|
|
+ * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
|
|
|
+ */
|
|
|
+ tcp_v6_send_ack(skb, (sk->sk_state == TCP_LISTEN) ?
|
|
|
+ tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,
|
|
|
+ tcp_rsk(req)->rcv_nxt,
|
|
|
req->rcv_wnd, tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if,
|
|
|
tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),
|
|
|
0, 0);
|
|
@@ -978,8 +984,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
__u32 isn = TCP_SKB_CB(skb)->when;
|
|
|
struct dst_entry *dst = NULL;
|
|
|
+ struct tcp_fastopen_cookie foc = { .len = -1 };
|
|
|
+ bool want_cookie = false, fastopen;
|
|
|
struct flowi6 fl6;
|
|
|
- bool want_cookie = false;
|
|
|
+ int err;
|
|
|
|
|
|
if (skb->protocol == htons(ETH_P_IP))
|
|
|
return tcp_v4_conn_request(sk, skb);
|
|
@@ -1010,7 +1018,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|
|
tcp_clear_options(&tmp_opt);
|
|
|
tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
|
|
|
tmp_opt.user_mss = tp->rx_opt.user_mss;
|
|
|
- tcp_parse_options(skb, &tmp_opt, 0, NULL);
|
|
|
+ tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc);
|
|
|
|
|
|
if (want_cookie && !tmp_opt.saw_tstamp)
|
|
|
tcp_clear_options(&tmp_opt);
|
|
@@ -1083,19 +1091,27 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|
|
isn = tcp_v6_init_sequence(skb);
|
|
|
}
|
|
|
have_isn:
|
|
|
- tcp_rsk(req)->snt_isn = isn;
|
|
|
|
|
|
if (security_inet_conn_request(sk, skb, req))
|
|
|
goto drop_and_release;
|
|
|
|
|
|
- if (tcp_v6_send_synack(sk, dst, &fl6, req,
|
|
|
- skb_get_queue_mapping(skb)) ||
|
|
|
- want_cookie)
|
|
|
+ if (!dst && (dst = inet6_csk_route_req(sk, &fl6, req)) == NULL)
|
|
|
goto drop_and_free;
|
|
|
|
|
|
+ tcp_rsk(req)->snt_isn = isn;
|
|
|
tcp_rsk(req)->snt_synack = tcp_time_stamp;
|
|
|
- tcp_rsk(req)->listener = NULL;
|
|
|
- inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
|
|
|
+ tcp_openreq_init_rwin(req, sk, dst);
|
|
|
+ fastopen = !want_cookie &&
|
|
|
+ tcp_try_fastopen(sk, skb, req, &foc, dst);
|
|
|
+ err = tcp_v6_send_synack(sk, dst, &fl6, req,
|
|
|
+ skb_get_queue_mapping(skb), &foc);
|
|
|
+ if (!fastopen) {
|
|
|
+ if (err || want_cookie)
|
|
|
+ goto drop_and_free;
|
|
|
+
|
|
|
+ tcp_rsk(req)->listener = NULL;
|
|
|
+ inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
|
|
|
+ }
|
|
|
return 0;
|
|
|
|
|
|
drop_and_release:
|