Merge branches 'fixes' and 'misc' into for-next
[deliverable/linux.git] / net / ipv4 / udp.c
index 0ff31d97d48586af00c6973d123576e040ed422a..5fdcb8d108d468ab33e8f29a21efdd643d27a49f 100644 (file)
@@ -391,9 +391,9 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
        return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr);
 }
 
-static inline int compute_score(struct sock *sk, struct net *net,
-                               __be32 saddr, unsigned short hnum, __be16 sport,
-                               __be32 daddr, __be16 dport, int dif)
+static int compute_score(struct sock *sk, struct net *net,
+                        __be32 saddr, __be16 sport,
+                        __be32 daddr, unsigned short hnum, int dif)
 {
        int score;
        struct inet_sock *inet;
@@ -434,52 +434,6 @@ static inline int compute_score(struct sock *sk, struct net *net,
        return score;
 }
 
-/*
- * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num)
- */
-static inline int compute_score2(struct sock *sk, struct net *net,
-                                __be32 saddr, __be16 sport,
-                                __be32 daddr, unsigned int hnum, int dif)
-{
-       int score;
-       struct inet_sock *inet;
-
-       if (!net_eq(sock_net(sk), net) ||
-           ipv6_only_sock(sk))
-               return -1;
-
-       inet = inet_sk(sk);
-
-       if (inet->inet_rcv_saddr != daddr ||
-           inet->inet_num != hnum)
-               return -1;
-
-       score = (sk->sk_family == PF_INET) ? 2 : 1;
-
-       if (inet->inet_daddr) {
-               if (inet->inet_daddr != saddr)
-                       return -1;
-               score += 4;
-       }
-
-       if (inet->inet_dport) {
-               if (inet->inet_dport != sport)
-                       return -1;
-               score += 4;
-       }
-
-       if (sk->sk_bound_dev_if) {
-               if (sk->sk_bound_dev_if != dif)
-                       return -1;
-               score += 4;
-       }
-
-       if (sk->sk_incoming_cpu == raw_smp_processor_id())
-               score++;
-
-       return score;
-}
-
 static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
                       const __u16 lport, const __be32 faddr,
                       const __be16 fport)
@@ -492,11 +446,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
                              udp_ehash_secret + net_hash_mix(net));
 }
 
-/* called with read_rcu_lock() */
+/* called with rcu_read_lock() */
 static struct sock *udp4_lib_lookup2(struct net *net,
                __be32 saddr, __be16 sport,
                __be32 daddr, unsigned int hnum, int dif,
-               struct udp_hslot *hslot2, unsigned int slot2,
+               struct udp_hslot *hslot2,
                struct sk_buff *skb)
 {
        struct sock *sk, *result;
@@ -506,7 +460,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
        result = NULL;
        badness = 0;
        udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-               score = compute_score2(sk, net, saddr, sport,
+               score = compute_score(sk, net, saddr, sport,
                                      daddr, hnum, dif);
                if (score > badness) {
                        reuseport = sk->sk_reuseport;
@@ -554,17 +508,22 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 
                result = udp4_lib_lookup2(net, saddr, sport,
                                          daddr, hnum, dif,
-                                         hslot2, slot2, skb);
+                                         hslot2, skb);
                if (!result) {
+                       unsigned int old_slot2 = slot2;
                        hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
                        slot2 = hash2 & udptable->mask;
+                       /* avoid searching the same slot again. */
+                       if (unlikely(slot2 == old_slot2))
+                               return result;
+
                        hslot2 = &udptable->hash2[slot2];
                        if (hslot->count < hslot2->count)
                                goto begin;
 
                        result = udp4_lib_lookup2(net, saddr, sport,
-                                                 htonl(INADDR_ANY), hnum, dif,
-                                                 hslot2, slot2, skb);
+                                                 daddr, hnum, dif,
+                                                 hslot2, skb);
                }
                return result;
        }
@@ -572,8 +531,8 @@ begin:
        result = NULL;
        badness = 0;
        sk_for_each_rcu(sk, &hslot->head) {
-               score = compute_score(sk, net, saddr, hnum, sport,
-                                     daddr, dport, dif);
+               score = compute_score(sk, net, saddr, sport,
+                                     daddr, hnum, dif);
                if (score > badness) {
                        reuseport = sk->sk_reuseport;
                        if (reuseport) {
@@ -1223,13 +1182,13 @@ out:
  *     @sk: socket
  *
  *     Drops all bad checksum frames, until a valid one is found.
- *     Returns the length of found skb, or 0 if none is found.
+ *     Returns the length of found skb, or -1 if none is found.
  */
-static unsigned int first_packet_length(struct sock *sk)
+static int first_packet_length(struct sock *sk)
 {
        struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue;
        struct sk_buff *skb;
-       unsigned int res;
+       int res;
 
        __skb_queue_head_init(&list_kill);
 
@@ -1244,7 +1203,7 @@ static unsigned int first_packet_length(struct sock *sk)
                __skb_unlink(skb, rcvq);
                __skb_queue_tail(&list_kill, skb);
        }
-       res = skb ? skb->len : 0;
+       res = skb ? skb->len : -1;
        spin_unlock_bh(&rcvq->lock);
 
        if (!skb_queue_empty(&list_kill)) {
@@ -1273,7 +1232,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 
        case SIOCINQ:
        {
-               unsigned int amount = first_packet_length(sk);
+               int amount = max_t(int, 0, first_packet_length(sk));
 
                return put_user(amount, (int __user *)arg);
        }
@@ -1622,7 +1581,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
            udp_lib_checksum_complete(skb))
                        goto csum_error;
 
-       if (sk_filter(sk, skb))
+       if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr)))
                goto drop;
 
        udp_csum_pull_header(skb);
@@ -1755,8 +1714,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
                        return err;
        }
 
-       return skb_checksum_init_zero_check(skb, proto, uh->check,
-                                           inet_compute_pseudo);
+       /* Note, we are only interested in != 0 or == 0, thus the
+        * force to int.
+        */
+       return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check,
+                                                        inet_compute_pseudo);
 }
 
 /*
@@ -2222,7 +2184,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
 
        /* Check for false positives due to checksum errors */
        if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) &&
-           !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk))
+           !(sk->sk_shutdown & RCV_SHUTDOWN) && first_packet_length(sk) == -1)
                mask &= ~(POLLIN | POLLRDNORM);
 
        return mask;
@@ -2254,7 +2216,6 @@ struct proto udp_prot = {
        .sysctl_wmem       = &sysctl_udp_wmem_min,
        .sysctl_rmem       = &sysctl_udp_rmem_min,
        .obj_size          = sizeof(struct udp_sock),
-       .slab_flags        = SLAB_DESTROY_BY_RCU,
        .h.udp_table       = &udp_table,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_udp_setsockopt,
This page took 0.054394 seconds and 5 git commands to generate.