Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
[pandora-kernel.git] / net / ipv4 / udp.c
index c36522a..50678f9 100644 (file)
@@ -233,7 +233,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                         */
                        do {
                                if (low <= snum && snum <= high &&
-                                   !test_bit(snum >> udptable->log, bitmap))
+                                   !test_bit(snum >> udptable->log, bitmap) &&
+                                   !inet_is_reserved_local_port(snum))
                                        goto found;
                                snum += rand;
                        } while (snum != first);
@@ -307,13 +308,13 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr,
                                       unsigned int port)
 {
-       return jhash_1word(saddr, net_hash_mix(net)) ^ port;
+       return jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port;
 }
 
 int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
        unsigned int hash2_nulladdr =
-               udp4_portaddr_hash(sock_net(sk), INADDR_ANY, snum);
+               udp4_portaddr_hash(sock_net(sk), htonl(INADDR_ANY), snum);
        unsigned int hash2_partial =
                udp4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0);
 
@@ -466,14 +467,14 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
                                          daddr, hnum, dif,
                                          hslot2, slot2);
                if (!result) {
-                       hash2 = udp4_portaddr_hash(net, INADDR_ANY, hnum);
+                       hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
                        slot2 = hash2 & udptable->mask;
                        hslot2 = &udptable->hash2[slot2];
                        if (hslot->count < hslot2->count)
                                goto begin;
 
                        result = udp4_lib_lookup2(net, saddr, sport,
-                                                 INADDR_ANY, hnum, dif,
+                                                 htonl(INADDR_ANY), hnum, dif,
                                                  hslot2, slot2);
                }
                rcu_read_unlock();
@@ -633,7 +634,9 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
                if (!harderr || sk->sk_state != TCP_ESTABLISHED)
                        goto out;
        } else {
+               bh_lock_sock(sk);
                ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1));
+               bh_unlock_sock(sk);
        }
        sk->sk_err = err;
        sk->sk_error_report(sk);
@@ -1062,10 +1065,11 @@ static unsigned int first_packet_length(struct sock *sk)
        spin_unlock_bh(&rcvq->lock);
 
        if (!skb_queue_empty(&list_kill)) {
-               lock_sock(sk);
+               bool slow = lock_sock_fast(sk);
+
                __skb_queue_purge(&list_kill);
                sk_mem_reclaim_partial(sk);
-               release_sock(sk);
+               unlock_sock_fast(sk, slow);
        }
        return res;
 }
@@ -1122,6 +1126,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        int peeked;
        int err;
        int is_udplite = IS_UDPLITE(sk);
+       bool slow;
 
        /*
         *      Check any passed addresses
@@ -1196,10 +1201,10 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock(sk);
+       slow = lock_sock_fast(sk);
        if (!skb_kill_datagram(sk, skb, flags))
                UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
-       release_sock(sk);
+       unlock_sock_fast(sk, slow);
 
        if (noblock)
                return -EAGAIN;
@@ -1217,6 +1222,7 @@ int udp_disconnect(struct sock *sk, int flags)
        sk->sk_state = TCP_CLOSE;
        inet->inet_daddr = 0;
        inet->inet_dport = 0;
+       sock_rps_save_rxhash(sk, 0);
        sk->sk_bound_dev_if = 0;
        if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
                inet_reset_saddr(sk);
@@ -1258,8 +1264,12 @@ EXPORT_SYMBOL(udp_lib_unhash);
 
 static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-       int rc = sock_queue_rcv_skb(sk, skb);
+       int rc;
 
+       if (inet_sk(sk)->inet_daddr)
+               sock_rps_save_rxhash(sk, skb->rxhash);
+
+       rc = ip_queue_rcv_skb(sk, skb);
        if (rc < 0) {
                int is_udplite = IS_UDPLITE(sk);
 
@@ -1367,6 +1377,10 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        goto drop;
        }
 
+
+       if (sk_rcvqueues_full(sk, skb))
+               goto drop;
+
        rc = 0;
 
        bh_lock_sock(sk);
@@ -1615,9 +1629,9 @@ int udp_rcv(struct sk_buff *skb)
 
 void udp_destroy_sock(struct sock *sk)
 {
-       lock_sock(sk);
+       bool slow = lock_sock_fast(sk);
        udp_flush_pending_frames(sk);
-       release_sock(sk);
+       unlock_sock_fast(sk, slow);
 }
 
 /*
@@ -1676,8 +1690,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        return -ENOPROTOOPT;
                if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
                        val = 8;
-               else if (val > USHORT_MAX)
-                       val = USHORT_MAX;
+               else if (val > USHRT_MAX)
+                       val = USHRT_MAX;
                up->pcslen = val;
                up->pcflag |= UDPLITE_SEND_CC;
                break;
@@ -1690,8 +1704,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                        return -ENOPROTOOPT;
                if (val != 0 && val < 8) /* Avoid silly minimal values.       */
                        val = 8;
-               else if (val > USHORT_MAX)
-                       val = USHORT_MAX;
+               else if (val > USHRT_MAX)
+                       val = USHRT_MAX;
                up->pcrlen = val;
                up->pcflag |= UDPLITE_RECV_CC;
                break;