To modify Ixia port numbers and IP in pod.yaml
[kvmfornfv.git] / kernel / net / dccp / ipv4.c
index ccf4c56..0759f5b 100644 (file)
@@ -204,11 +204,8 @@ void dccp_req_err(struct sock *sk, u64 seq)
         * ICMPs are not backlogged, hence we cannot get an established
         * socket here.
         */
-       WARN_ON(req->sk);
-
        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 +215,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);
 
@@ -237,7 +235,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
 {
        const struct iphdr *iph = (struct iphdr *)skb->data;
        const u8 offset = iph->ihl << 2;
-       const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);
+       const struct dccp_hdr *dh;
        struct dccp_sock *dp;
        struct inet_sock *inet;
        const int type = icmp_hdr(skb)->type;
@@ -247,11 +245,13 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
        int err;
        struct net *net = dev_net(skb->dev);
 
-       if (skb->len < offset + sizeof(*dh) ||
-           skb->len < offset + __dccp_basic_hdr_len(dh)) {
-               ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
-               return;
-       }
+       /* Only need dccph_dport & dccph_sport which are the first
+        * 4 bytes in dccp header.
+        * Our caller (icmp_socket_deliver()) already pulled 8 bytes for us.
+        */
+       BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_sport) > 8);
+       BUILD_BUG_ON(offsetofend(struct dccp_hdr, dccph_dport) > 8);
+       dh = (struct dccp_hdr *)(skb->data + offset);
 
        sk = __inet_lookup_established(net, &dccp_hashinfo,
                                       iph->daddr, dh->dccph_dport,
@@ -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;
 }
@@ -738,6 +698,7 @@ int dccp_invalid_packet(struct sk_buff *skb)
 {
        const struct dccp_hdr *dh;
        unsigned int cscov;
+       u8 dccph_doff;
 
        if (skb->pkt_type != PACKET_HOST)
                return 1;
@@ -759,18 +720,19 @@ int dccp_invalid_packet(struct sk_buff *skb)
        /*
         * If P.Data Offset is too small for packet type, drop packet and return
         */
-       if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
-               DCCP_WARN("P.Data Offset(%u) too small\n", dh->dccph_doff);
+       dccph_doff = dh->dccph_doff;
+       if (dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
+               DCCP_WARN("P.Data Offset(%u) too small\n", dccph_doff);
                return 1;
        }
        /*
         * If P.Data Offset is too too large for packet, drop packet and return
         */
-       if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {
-               DCCP_WARN("P.Data Offset(%u) too large\n", dh->dccph_doff);
+       if (!pskb_may_pull(skb, dccph_doff * sizeof(u32))) {
+               DCCP_WARN("P.Data Offset(%u) too large\n", dccph_doff);
                return 1;
        }
-
+       dh = dccp_hdr(skb);
        /*
         * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet
         * has short sequence numbers), drop packet and return
@@ -841,15 +803,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 +824,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