These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / dccp / ipv4.c
index ccf4c56..902d606 100644 (file)
@@ -208,7 +208,6 @@ void dccp_req_err(struct sock *sk, u64 seq)
 
        if (!between48(seq, dccp_rsk(req)->dreq_iss, dccp_rsk(req)->dreq_gss)) {
                NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
-               reqsk_put(req);
        } else {
                /*
                 * Still in RESPOND, just remove it silently.
@@ -218,6 +217,7 @@ void dccp_req_err(struct sock *sk, u64 seq)
                 */
                inet_csk_reqsk_queue_drop(req->rsk_listener, req);
        }
+       reqsk_put(req);
 }
 EXPORT_SYMBOL(dccp_req_err);
 
@@ -390,9 +390,12 @@ static inline u64 dccp_v4_init_sequence(const struct sk_buff *skb)
  *
  * This is the equivalent of TCP's tcp_v4_syn_recv_sock
  */
-struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
+struct sock *dccp_v4_request_recv_sock(const struct sock *sk,
+                                      struct sk_buff *skb,
                                       struct request_sock *req,
-                                      struct dst_entry *dst)
+                                      struct dst_entry *dst,
+                                      struct request_sock *req_unhash,
+                                      bool *own_req)
 {
        struct inet_request_sock *ireq;
        struct inet_sock *newinet;
@@ -425,7 +428,7 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        if (__inet_inherit_port(sk, newsk) < 0)
                goto put_and_exit;
-       __inet_hash_nolisten(newsk, NULL);
+       *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
 
        return newsk;
 
@@ -443,36 +446,6 @@ put_and_exit:
 }
 EXPORT_SYMBOL_GPL(dccp_v4_request_recv_sock);
 
-static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
-{
-       const struct dccp_hdr *dh = dccp_hdr(skb);
-       const struct iphdr *iph = ip_hdr(skb);
-       struct sock *nsk;
-       /* Find possible connection requests. */
-       struct request_sock *req = inet_csk_search_req(sk, dh->dccph_sport,
-                                                      iph->saddr, iph->daddr);
-       if (req) {
-               nsk = dccp_check_req(sk, skb, req);
-               if (!nsk)
-                       reqsk_put(req);
-               return nsk;
-       }
-       nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo,
-                                     iph->saddr, dh->dccph_sport,
-                                     iph->daddr, dh->dccph_dport,
-                                     inet_iif(skb));
-       if (nsk != NULL) {
-               if (nsk->sk_state != DCCP_TIME_WAIT) {
-                       bh_lock_sock(nsk);
-                       return nsk;
-               }
-               inet_twsk_put(inet_twsk(nsk));
-               return NULL;
-       }
-
-       return sk;
-}
-
 static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
                                           struct sk_buff *skb)
 {
@@ -498,7 +471,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
        return &rt->dst;
 }
 
-static int dccp_v4_send_response(struct sock *sk, struct request_sock *req)
+static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req)
 {
        int err = -1;
        struct sk_buff *skb;
@@ -527,7 +500,7 @@ out:
        return err;
 }
 
-static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
+static void dccp_v4_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb)
 {
        int err;
        const struct iphdr *rxiph;
@@ -624,7 +597,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
                goto drop;
 
-       req = inet_reqsk_alloc(&dccp_request_sock_ops, sk);
+       req = inet_reqsk_alloc(&dccp_request_sock_ops, sk, true);
        if (req == NULL)
                goto drop;
 
@@ -704,18 +677,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
         * NOTE: the check for the packet types is done in
         *       dccp_rcv_state_process
         */
-       if (sk->sk_state == DCCP_LISTEN) {
-               struct sock *nsk = dccp_v4_hnd_req(sk, skb);
-
-               if (nsk == NULL)
-                       goto discard;
-
-               if (nsk != sk) {
-                       if (dccp_child_process(sk, nsk, skb))
-                               goto reset;
-                       return 0;
-               }
-       }
 
        if (dccp_rcv_state_process(sk, skb, dh, skb->len))
                goto reset;
@@ -723,7 +684,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 
 reset:
        dccp_v4_ctl_send_reset(sk, skb);
-discard:
        kfree_skb(skb);
        return 0;
 }
@@ -841,15 +801,10 @@ static int dccp_v4_rcv(struct sk_buff *skb)
                                  DCCP_SKB_CB(skb)->dccpd_ack_seq);
        }
 
-       /* Step 2:
-        *      Look up flow ID in table and get corresponding socket */
+lookup:
        sk = __inet_lookup_skb(&dccp_hashinfo, skb,
                               dh->dccph_sport, dh->dccph_dport);
-       /*
-        * Step 2:
-        *      If no socket ...
-        */
-       if (sk == NULL) {
+       if (!sk) {
                dccp_pr_debug("failed to look up flow ID in table and "
                              "get corresponding socket\n");
                goto no_dccp_socket;
@@ -867,6 +822,31 @@ static int dccp_v4_rcv(struct sk_buff *skb)
                goto no_dccp_socket;
        }
 
+       if (sk->sk_state == DCCP_NEW_SYN_RECV) {
+               struct request_sock *req = inet_reqsk(sk);
+               struct sock *nsk;
+
+               sk = req->rsk_listener;
+               if (unlikely(sk->sk_state != DCCP_LISTEN)) {
+                       inet_csk_reqsk_queue_drop_and_put(sk, req);
+                       goto lookup;
+               }
+               sock_hold(sk);
+               nsk = dccp_check_req(sk, skb, req);
+               if (!nsk) {
+                       reqsk_put(req);
+                       goto discard_and_relse;
+               }
+               if (nsk == sk) {
+                       reqsk_put(req);
+               } else if (dccp_child_process(sk, nsk, skb)) {
+                       dccp_v4_ctl_send_reset(sk, skb);
+                       goto discard_and_relse;
+               } else {
+                       sock_put(sk);
+                       return 0;
+               }
+       }
        /*
         * RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
         *      o if MinCsCov = 0, only packets with CsCov = 0 are accepted