Merge branch 'acpi-cleanup' into fixes
[cascardo/linux.git] / net / ipv6 / udp.c
index fb08329..599e1ba 100644 (file)
@@ -45,6 +45,7 @@
 #include <net/tcp_states.h>
 #include <net/ip6_checksum.h>
 #include <net/xfrm.h>
+#include <net/inet6_hashtables.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net,
 {
        struct sock *sk, *result;
        struct hlist_nulls_node *node;
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
 begin:
        result = NULL;
@@ -214,8 +216,18 @@ begin:
                if (score > badness) {
                        result = sk;
                        badness = score;
-                       if (score == SCORE2_MAX)
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet6_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       } else if (score == SCORE2_MAX)
                                goto exact_match;
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net,
        unsigned short hnum = ntohs(dport);
        unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
        struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
-       int score, badness;
+       int score, badness, matches = 0, reuseport = 0;
+       u32 hash = 0;
 
        rcu_read_lock();
        if (hslot->count > 10) {
@@ -284,6 +297,17 @@ begin:
                if (score > badness) {
                        result = sk;
                        badness = score;
+                       reuseport = sk->sk_reuseport;
+                       if (reuseport) {
+                               hash = inet6_ehashfn(net, daddr, hnum,
+                                                    saddr, sport);
+                               matches = 1;
+                       }
+               } else if (score == badness && reuseport) {
+                       matches++;
+                       if (((u64)hash * matches) >> 32 == 0)
+                               result = sk;
+                       hash = next_pseudo_random32(hash);
                }
        }
        /*
@@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
        return 0;
 }
 
-static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
-                                int proto)
-{
-       int err;
-
-       UDP_SKB_CB(skb)->partial_cov = 0;
-       UDP_SKB_CB(skb)->cscov = skb->len;
-
-       if (proto == IPPROTO_UDPLITE) {
-               err = udplite_checksum_init(skb, uh);
-               if (err)
-                       return err;
-       }
-
-       if (uh->check == 0) {
-               /* RFC 2460 section 8.1 says that we SHOULD log
-                  this error. Well, it is reasonable.
-                */
-               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
-               return 1;
-       }
-       if (skb->ip_summed == CHECKSUM_COMPLETE &&
-           !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
-                            skb->len, proto, skb->csum))
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       if (!skb_csum_unnecessary(skb))
-               skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                        &ipv6_hdr(skb)->daddr,
-                                                        skb->len, proto, 0));
-
-       return 0;
-}
-
 int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                   int proto)
 {