ipv4: Only compute net once in ip_call_ra_chain
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / tcp_minisocks.c
index def765911ff85dfefd2c73c41b6585b33c77bcea..41828bdc5d32ad13526dcc0c390f09604e67d9d9 100644 (file)
@@ -361,30 +361,38 @@ void tcp_twsk_destructor(struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
 
+/* Warning : This function is called without sk_listener being locked.
+ * Be sure to read socket fields once, as their value could change under us.
+ */
 void tcp_openreq_init_rwin(struct request_sock *req,
-                          struct sock *sk, struct dst_entry *dst)
+                          const struct sock *sk_listener,
+                          const struct dst_entry *dst)
 {
        struct inet_request_sock *ireq = inet_rsk(req);
-       struct tcp_sock *tp = tcp_sk(sk);
-       __u8 rcv_wscale;
+       const struct tcp_sock *tp = tcp_sk(sk_listener);
+       u16 user_mss = READ_ONCE(tp->rx_opt.user_mss);
+       int full_space = tcp_full_space(sk_listener);
        int mss = dst_metric_advmss(dst);
+       u32 window_clamp;
+       __u8 rcv_wscale;
 
-       if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
-               mss = tp->rx_opt.user_mss;
+       if (user_mss && user_mss < mss)
+               mss = user_mss;
 
+       window_clamp = READ_ONCE(tp->window_clamp);
        /* Set this up on the first call only */
-       req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
+       req->rsk_window_clamp = window_clamp ? : dst_metric(dst, RTAX_WINDOW);
 
        /* limit the window selection if the user enforce a smaller rx buffer */
-       if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
-           (req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
-               req->window_clamp = tcp_full_space(sk);
+       if (sk_listener->sk_userlocks & SOCK_RCVBUF_LOCK &&
+           (req->rsk_window_clamp > full_space || req->rsk_window_clamp == 0))
+               req->rsk_window_clamp = full_space;
 
        /* tcp_full_space because it is guaranteed to be the first packet */
-       tcp_select_initial_window(tcp_full_space(sk),
+       tcp_select_initial_window(full_space,
                mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
-               &req->rcv_wnd,
-               &req->window_clamp,
+               &req->rsk_rcv_wnd,
+               &req->rsk_window_clamp,
                ireq->wscale_ok,
                &rcv_wscale,
                dst_metric(dst, RTAX_INITRWND));
@@ -433,7 +441,9 @@ EXPORT_SYMBOL_GPL(tcp_ca_openreq_child);
  * Actually, we could lots of memory writes here. tp of listening
  * socket contains all necessary default parameters.
  */
-struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)
+struct sock *tcp_create_openreq_child(const struct sock *sk,
+                                     struct request_sock *req,
+                                     struct sk_buff *skb)
 {
        struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
 
@@ -469,7 +479,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
                tcp_enable_early_retrans(newtp);
                newtp->tlp_high_seq = 0;
-               newtp->lsndtime = treq->snt_synack;
+               newtp->lsndtime = treq->snt_synack.stamp_jiffies;
+               newsk->sk_txhash = treq->txhash;
                newtp->last_oow_ack_time = 0;
                newtp->total_retrans = req->num_retrans;
 
@@ -501,9 +512,9 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                        if (sysctl_tcp_fack)
                                tcp_enable_fack(newtp);
                }
-               newtp->window_clamp = req->window_clamp;
-               newtp->rcv_ssthresh = req->rcv_wnd;
-               newtp->rcv_wnd = req->rcv_wnd;
+               newtp->window_clamp = req->rsk_window_clamp;
+               newtp->rcv_ssthresh = req->rsk_rcv_wnd;
+               newtp->rcv_wnd = req->rsk_rcv_wnd;
                newtp->rx_opt.wscale_ok = ireq->wscale_ok;
                if (newtp->rx_opt.wscale_ok) {
                        newtp->rx_opt.snd_wscale = ireq->snd_wscale;
@@ -567,8 +578,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
        bool paws_reject = false;
 
-       BUG_ON(fastopen == (sk->sk_state == TCP_LISTEN));
-
        tmp_opt.saw_tstamp = 0;
        if (th->doff > (sizeof(struct tcphdr)>>2)) {
                tcp_parse_options(skb, &tmp_opt, 0, NULL);
@@ -698,7 +707,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        /* RFC793: "first check sequence number". */
 
        if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-                                         tcp_rsk(req)->rcv_nxt, tcp_rsk(req)->rcv_nxt + req->rcv_wnd)) {
+                                         tcp_rsk(req)->rcv_nxt, tcp_rsk(req)->rcv_nxt + req->rsk_rcv_wnd)) {
                /* Out of window: send ACK and drop. */
                if (!(flg & TCP_FLAG_RST))
                        req->rsk_ops->send_ack(sk, skb, req);
@@ -759,6 +768,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        if (!child)
                goto listen_overflow;
 
+       sock_rps_save_rxhash(child, skb);
+       tcp_synack_rtt_meas(child, req);
        inet_csk_reqsk_queue_drop(sk, req);
        inet_csk_reqsk_queue_add(sk, req, child);
        /* Warning: caller must not call reqsk_put(req);
@@ -811,8 +822,7 @@ int tcp_child_process(struct sock *parent, struct sock *child,
        int state = child->sk_state;
 
        if (!sock_owned_by_user(child)) {
-               ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb),
-                                           skb->len);
+               ret = tcp_rcv_state_process(child, skb);
                /* Wakeup parent, send SIGIO */
                if (state == TCP_SYN_RECV && child->sk_state != state)
                        parent->sk_data_ready(parent);