Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[sfrench/cifs-2.6.git] / net / ipv4 / inet_connection_sock.c
index 94468a76c5b4e0f70bca33afcf0c5b95cf654a7c..9a01bb81f8bf99f5d4202e7e459b88d597170621 100644 (file)
@@ -37,7 +37,8 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
  */
 int sysctl_local_port_range[2] = { 1024, 4999 };
 
-static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucket *tb)
+int inet_csk_bind_conflict(const struct sock *sk,
+                          const struct inet_bind_bucket *tb)
 {
        const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
        struct sock *sk2;
@@ -62,11 +63,15 @@ static inline int inet_csk_bind_conflict(struct sock *sk, struct inet_bind_bucke
        return node != NULL;
 }
 
+EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
+
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
  */
 int inet_csk_get_port(struct inet_hashinfo *hashinfo,
-                     struct sock *sk, unsigned short snum)
+                     struct sock *sk, unsigned short snum,
+                     int (*bind_conflict)(const struct sock *sk,
+                                          const struct inet_bind_bucket *tb))
 {
        struct inet_bind_hashbucket *head;
        struct hlist_node *node;
@@ -78,17 +83,9 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
                int low = sysctl_local_port_range[0];
                int high = sysctl_local_port_range[1];
                int remaining = (high - low) + 1;
-               int rover;
+               int rover = net_random() % (high - low) + low;
 
-               spin_lock(&hashinfo->portalloc_lock);
-               if (hashinfo->port_rover < low)
-                       rover = low;
-               else
-                       rover = hashinfo->port_rover;
                do {
-                       rover++;
-                       if (rover > high)
-                               rover = low;
                        head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
                        spin_lock(&head->lock);
                        inet_bind_bucket_for_each(tb, node, &head->chain)
@@ -97,9 +94,9 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
                        break;
                next:
                        spin_unlock(&head->lock);
+                       if (++rover > high)
+                               rover = low;
                } while (--remaining > 0);
-               hashinfo->port_rover = rover;
-               spin_unlock(&hashinfo->portalloc_lock);
 
                /* Exhausted local port range during search?  It is not
                 * possible for us to be holding one of the bind hash
@@ -133,7 +130,7 @@ tb_found:
                        goto success;
                } else {
                        ret = 1;
-                       if (inet_csk_bind_conflict(sk, tb))
+                       if (bind_conflict(sk, tb))
                                goto fail_unlock;
                }
        }
@@ -388,7 +385,7 @@ struct request_sock *inet_csk_search_req(const struct sock *sk,
 EXPORT_SYMBOL_GPL(inet_csk_search_req);
 
 void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
-                                  const unsigned timeout)
+                                  unsigned long timeout)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
@@ -639,3 +636,64 @@ void inet_csk_listen_stop(struct sock *sk)
 }
 
 EXPORT_SYMBOL_GPL(inet_csk_listen_stop);
+
+void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
+       const struct inet_sock *inet = inet_sk(sk);
+
+       sin->sin_family         = AF_INET;
+       sin->sin_addr.s_addr    = inet->daddr;
+       sin->sin_port           = inet->dport;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
+
+int inet_csk_ctl_sock_create(struct socket **sock, unsigned short family,
+                            unsigned short type, unsigned char protocol)
+{
+       int rc = sock_create_kern(family, type, protocol, sock);
+
+       if (rc == 0) {
+               (*sock)->sk->sk_allocation = GFP_ATOMIC;
+               inet_sk((*sock)->sk)->uc_ttl = -1;
+               /*
+                * Unhash it so that IP input processing does not even see it,
+                * we do not wish this socket to see incoming packets.
+                */
+               (*sock)->sk->sk_prot->unhash((*sock)->sk);
+       }
+       return rc;
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_ctl_sock_create);
+
+#ifdef CONFIG_COMPAT
+int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname,
+                              char __user *optval, int __user *optlen)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_af_ops->compat_getsockopt != NULL)
+               return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname,
+                                                           optval, optlen);
+       return icsk->icsk_af_ops->getsockopt(sk, level, optname,
+                                            optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt);
+
+int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname,
+                              char __user *optval, int optlen)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       if (icsk->icsk_af_ops->compat_setsockopt != NULL)
+               return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname,
+                                                           optval, optlen);
+       return icsk->icsk_af_ops->setsockopt(sk, level, optname,
+                                            optval, optlen);
+}
+
+EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
+#endif