]> err.no Git - linux-2.6/blobdiff - net/ipv4/udp.c
[ARP]: Minus one level of ndentation in arp_req_delete
[linux-2.6] / net / ipv4 / udp.c
index 69d4bd10f9c6ef31e5ce3c9762486bd61ab98bda..9ed6393c65d976298a4fb9ddca046cc8b4e338f5 100644 (file)
@@ -98,6 +98,7 @@
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <net/net_namespace.h>
 #include <net/icmp.h>
 #include <net/route.h>
 #include <net/checksum.h>
  */
 
 DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly;
+EXPORT_SYMBOL(udp_statistics);
 
 struct hlist_head udp_hash[UDP_HTABLE_SIZE];
 DEFINE_RWLOCK(udp_hash_lock);
 
-static int udp_port_rover;
-
-static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])
+static inline int __udp_lib_lport_inuse(__u16 num,
+                                       const struct hlist_head udptable[])
 {
        struct sock *sk;
        struct hlist_node *node;
@@ -132,11 +133,10 @@ static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])
  *  @sk:          socket struct in question
  *  @snum:        port number to look up
  *  @udptable:    hash list table, must be of UDP_HTABLE_SIZE
- *  @port_rover:  pointer to record of last unallocated port
  *  @saddr_comp:  AF-dependent comparison of bound local IP addresses
  */
 int __udp_lib_get_port(struct sock *sk, unsigned short snum,
-                      struct hlist_head udptable[], int *port_rover,
+                      struct hlist_head udptable[],
                       int (*saddr_comp)(const struct sock *sk1,
                                         const struct sock *sk2 )    )
 {
@@ -146,49 +146,57 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
        int    error = 1;
 
        write_lock_bh(&udp_hash_lock);
-       if (snum == 0) {
-               int best_size_so_far, best, result, i;
-
-               if (*port_rover > sysctl_local_port_range[1] ||
-                   *port_rover < sysctl_local_port_range[0])
-                       *port_rover = sysctl_local_port_range[0];
-               best_size_so_far = 32767;
-               best = result = *port_rover;
-               for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
-                       int size;
-
-                       head = &udptable[result & (UDP_HTABLE_SIZE - 1)];
-                       if (hlist_empty(head)) {
-                               if (result > sysctl_local_port_range[1])
-                                       result = sysctl_local_port_range[0] +
-                                               ((result - sysctl_local_port_range[0]) &
-                                                (UDP_HTABLE_SIZE - 1));
+
+       if (!snum) {
+               int i, low, high, remaining;
+               unsigned rover, best, best_size_so_far;
+
+               inet_get_local_port_range(&low, &high);
+               remaining = (high - low) + 1;
+
+               best_size_so_far = UINT_MAX;
+               best = rover = net_random() % remaining + low;
+
+               /* 1st pass: look for empty (or shortest) hash chain */
+               for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+                       int size = 0;
+
+                       head = &udptable[rover & (UDP_HTABLE_SIZE - 1)];
+                       if (hlist_empty(head))
                                goto gotit;
-                       }
-                       size = 0;
+
                        sk_for_each(sk2, node, head) {
                                if (++size >= best_size_so_far)
                                        goto next;
                        }
                        best_size_so_far = size;
-                       best = result;
+                       best = rover;
                next:
-                       ;
+                       /* fold back if end of range */
+                       if (++rover > high)
+                               rover = low + ((rover - low)
+                                              & (UDP_HTABLE_SIZE - 1));
+
+
                }
-               result = best;
-               for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE;
-                    i++, result += UDP_HTABLE_SIZE) {
-                       if (result > sysctl_local_port_range[1])
-                               result = sysctl_local_port_range[0]
-                                       + ((result - sysctl_local_port_range[0]) &
-                                          (UDP_HTABLE_SIZE - 1));
-                       if (! __udp_lib_lport_inuse(result, udptable))
-                               break;
+
+               /* 2nd pass: find hole in shortest hash chain */
+               rover = best;
+               for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
+                       if (! __udp_lib_lport_inuse(rover, udptable))
+                               goto gotit;
+                       rover += UDP_HTABLE_SIZE;
+                       if (rover > high)
+                               rover = low + ((rover - low)
+                                              & (UDP_HTABLE_SIZE - 1));
                }
-               if (i >= (1 << 16) / UDP_HTABLE_SIZE)
-                       goto fail;
+
+
+               /* All ports in use! */
+               goto fail;
+
 gotit:
-               *port_rover = snum = result;
+               snum = rover;
        } else {
                head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
 
@@ -201,6 +209,7 @@ gotit:
                            (*saddr_comp)(sk, sk2)                             )
                                goto fail;
        }
+
        inet_sk(sk)->num = snum;
        sk->sk_hash = snum;
        if (sk_unhashed(sk)) {
@@ -217,7 +226,7 @@ fail:
 int udp_get_port(struct sock *sk, unsigned short snum,
                        int (*scmp)(const struct sock *, const struct sock *))
 {
-       return  __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
+       return  __udp_lib_get_port(sk, snum, udp_hash, scmp);
 }
 
 int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
@@ -463,6 +472,7 @@ static int udp_push_pending_frames(struct sock *sk)
        struct sk_buff *skb;
        struct udphdr *uh;
        int err = 0;
+       int is_udplite = IS_UDPLITE(sk);
        __wsum csum = 0;
 
        /* Grab the skbuff where UDP header space exists. */
@@ -478,7 +488,7 @@ static int udp_push_pending_frames(struct sock *sk)
        uh->len = htons(up->len);
        uh->check = 0;
 
-       if (up->pcflag)                                  /*     UDP-Lite      */
+       if (is_udplite)                                  /*     UDP-Lite      */
                csum  = udplite_csum_outgoing(sk, skb);
 
        else if (sk->sk_no_check == UDP_CSUM_NOXMIT) {   /* UDP csum disabled */
@@ -506,7 +516,7 @@ out:
        up->len = 0;
        up->pending = 0;
        if (!err)
-               UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, up->pcflag);
+               UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite);
        return err;
 }
 
@@ -523,7 +533,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        __be32 daddr, faddr, saddr;
        __be16 dport;
        u8  tos;
-       int err, is_udplite = up->pcflag;
+       int err, is_udplite = IS_UDPLITE(sk);
        int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
        int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
 
@@ -817,6 +827,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
        struct sk_buff *skb;
        unsigned int ulen, copied;
+       int peeked;
        int err;
        int is_udplite = IS_UDPLITE(sk);
 
@@ -830,7 +841,8 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                return ip_recv_error(sk, msg, len);
 
 try_again:
-       skb = skb_recv_datagram(sk, flags, noblock, &err);
+       skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
+                                 &peeked, &err);
        if (!skb)
                goto out;
 
@@ -865,6 +877,9 @@ try_again:
        if (err)
                goto out_free;
 
+       if (!peeked)
+               UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite);
+
        sock_recv_timestamp(msg, sk, skb);
 
        /* Copy the address. */
@@ -888,9 +903,8 @@ out:
        return err;
 
 csum_copy_err:
-       UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
-
-       skb_kill_datagram(sk, skb, flags);
+       if (!skb_kill_datagram(sk, skb, flags))
+               UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
 
        if (noblock)
                return -EAGAIN;
@@ -932,6 +946,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
        struct udp_sock *up = udp_sk(sk);
        int rc;
+       int is_udplite = IS_UDPLITE(sk);
 
        /*
         *      Charge it to the socket, dropping if the queue is full.
@@ -959,7 +974,8 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 
                        ret = (*up->encap_rcv)(sk, skb);
                        if (ret <= 0) {
-                               UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
+                               UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS,
+                                                is_udplite);
                                return -ret;
                        }
                }
@@ -970,7 +986,7 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
        /*
         *      UDP-Lite specific tests, ignored on UDP sockets
         */
-       if ((up->pcflag & UDPLITE_RECV_CC)  &&  UDP_SKB_CB(skb)->partial_cov) {
+       if ((is_udplite & UDPLITE_RECV_CC)  &&  UDP_SKB_CB(skb)->partial_cov) {
 
                /*
                 * MIB statistics other than incrementing the error count are
@@ -1011,15 +1027,14 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
        if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
                /* Note that an ENOMEM error is charged twice */
                if (rc == -ENOMEM)
-                       UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag);
+                       UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite);
                goto drop;
        }
 
-       UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
        return 0;
 
 drop:
-       UDP_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag);
+       UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
        kfree_skb(skb);
        return -1;
 }
@@ -1144,7 +1159,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
                return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
 
        sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
-                              skb->dev->ifindex, udptable        );
+                              inet_iif(skb), udptable);
 
        if (sk != NULL) {
                int ret = udp_queue_rcv_skb(sk, skb);
@@ -1228,6 +1243,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
        struct udp_sock *up = udp_sk(sk);
        int val;
        int err = 0;
+       int is_udplite = IS_UDPLITE(sk);
 
        if (optlen<sizeof(int))
                return -EINVAL;
@@ -1269,7 +1285,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
        /* The sender sets actual checksum coverage length via this option.
         * The case coverage > packet length is handled by send module. */
        case UDPLITE_SEND_CSCOV:
-               if (!up->pcflag)         /* Disable the option on UDP sockets */
+               if (!is_udplite)         /* Disable the option on UDP sockets */
                        return -ENOPROTOOPT;
                if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
                        val = 8;
@@ -1281,7 +1297,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
         * sense, this should be set to at least 8 (as done below). If zero is
         * used, this again means full checksum coverage.                     */
        case UDPLITE_RECV_CSCOV:
-               if (!up->pcflag)         /* Disable the option on UDP sockets */
+               if (!is_udplite)         /* Disable the option on UDP sockets */
                        return -ENOPROTOOPT;
                if (val != 0 && val < 8) /* Avoid silly minimal values.       */
                        val = 8;
@@ -1422,6 +1438,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
 
 }
 
+DEFINE_PROTO_INUSE(udp)
+
 struct proto udp_prot = {
        .name              = "UDP",
        .owner             = THIS_MODULE,
@@ -1444,6 +1462,7 @@ struct proto udp_prot = {
        .compat_setsockopt = compat_udp_setsockopt,
        .compat_getsockopt = compat_udp_getsockopt,
 #endif
+       REF_PROTO_INUSE(udp)
 };
 
 /* ------------------------------------------------------------------------ */
@@ -1560,7 +1579,7 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo)
        afinfo->seq_fops->llseek        = seq_lseek;
        afinfo->seq_fops->release       = seq_release_private;
 
-       p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops);
+       p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);
        if (p)
                p->data = afinfo;
        else
@@ -1572,7 +1591,7 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo)
 {
        if (!afinfo)
                return;
-       proc_net_remove(afinfo->name);
+       proc_net_remove(&init_net, afinfo->name);
        memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
 }