vserver 1.9.3
[linux-2.6.git] / net / ipv4 / af_inet.c
index c4a967b..760516a 100644 (file)
@@ -122,11 +122,6 @@ atomic_t inet_sock_nr;
 
 extern void ip_mc_drop_socket(struct sock *sk);
 
-/* Per protocol sock slabcache */
-kmem_cache_t *tcp_sk_cachep;
-static kmem_cache_t *udp_sk_cachep;
-static kmem_cache_t *raw4_sk_cachep;
-
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
  */
@@ -159,7 +154,7 @@ void inet_sock_destruct(struct sock *sk)
 
        if (inet->opt)
                kfree(inet->opt);
-       
+
        vx_sock_dec(sk);
        clr_vx_info(&sk->sk_vx_info);
        sk->sk_xid = -1;
@@ -236,28 +231,6 @@ out:
        return err;
 }
 
-static __inline__ kmem_cache_t *inet_sk_slab(int protocol)
-{
-       kmem_cache_t* rc = tcp_sk_cachep;
-
-       if (protocol == IPPROTO_UDP)
-               rc = udp_sk_cachep;
-       else if (protocol == IPPROTO_RAW)
-               rc = raw4_sk_cachep;
-       return rc;
-}
-
-static __inline__ int inet_sk_size(int protocol)
-{
-       int rc = sizeof(struct tcp_sock);
-
-       if (protocol == IPPROTO_UDP)
-               rc = sizeof(struct udp_sock);
-       else if (protocol == IPPROTO_RAW)
-               rc = sizeof(struct raw_sock);
-       return rc;
-}
-
 /*
  *     Create an inet socket.
  */
@@ -268,13 +241,12 @@ static int inet_create(struct socket *sock, int protocol)
        struct list_head *p;
        struct inet_protosw *answer;
        struct inet_opt *inet;
-       int err = -ENOBUFS;
+       struct proto *answer_prot;
+       unsigned char answer_flags;
+       char answer_no_check;
+       int err;
 
        sock->state = SS_UNCONNECTED;
-       sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
-                     inet_sk_slab(protocol));
-       if (!sk)
-               goto out;
 
        /* Look for the requested type/protocol pair. */
        answer = NULL;
@@ -300,24 +272,38 @@ static int inet_create(struct socket *sock, int protocol)
 
        err = -ESOCKTNOSUPPORT;
        if (!answer)
-               goto out_sk_free;
+               goto out_rcu_unlock;
        err = -EPERM;
        if ((protocol == IPPROTO_ICMP) && vx_ccaps(VXC_RAW_ICMP))
                goto override;
        if (answer->capability > 0 && !capable(answer->capability))
-               goto out_sk_free;
+               goto out_rcu_unlock;
 override:
        err = -EPROTONOSUPPORT;
        if (!protocol)
-               goto out_sk_free;
-       err = 0;
+               goto out_rcu_unlock;
+
        sock->ops = answer->ops;
-       sk->sk_prot = answer->prot;
-       sk->sk_no_check = answer->no_check;
-       if (INET_PROTOSW_REUSE & answer->flags)
-               sk->sk_reuse = 1;
+       answer_prot = answer->prot;
+       answer_no_check = answer->no_check;
+       answer_flags = answer->flags;
        rcu_read_unlock();
 
+       BUG_TRAP(answer_prot->slab != NULL);
+
+       err = -ENOBUFS;
+       sk = sk_alloc(PF_INET, GFP_KERNEL,
+                     answer_prot->slab_obj_size,
+                     answer_prot->slab);
+       if (sk == NULL)
+               goto out;
+
+       err = 0;
+       sk->sk_prot = answer_prot;
+       sk->sk_no_check = answer_no_check;
+       if (INET_PROTOSW_REUSE & answer_flags)
+               sk->sk_reuse = 1;
+
        inet = inet_sk(sk);
 
        if (SOCK_RAW == sock->type) {
@@ -337,11 +323,10 @@ override:
        sk_set_owner(sk, THIS_MODULE);
 
        sk->sk_destruct    = inet_sock_destruct;
-       sk->sk_zapped      = 0;
        sk->sk_family      = PF_INET;
        sk->sk_protocol    = protocol;
        sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
-       
+
        set_vx_info(&sk->sk_vx_info, current->vx_info);
        sk->sk_xid = vx_current_xid();
        vx_sock_inc(sk);
@@ -376,9 +361,8 @@ override:
        }
 out:
        return err;
-out_sk_free:
+out_rcu_unlock:
        rcu_read_unlock();
-       sk_free(sk);
        goto out;
 }
 
@@ -432,8 +416,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        int chk_addr_ret;
        int err;
        __u32 s_addr;   /* Address used for validation */
-       __u32 s_addr1;
-       __u32 s_addr2 = 0xffffffffl;    /* Optional address of the socket */
+       __u32 s_addr1;  /* Address used for socket */
+       __u32 s_addr2;  /* Broadcast address for the socket */
        struct nx_info *nxi = sk->sk_nx_info;
 
        /* If the socket has its own bind function then use it. (RAW) */
@@ -445,38 +429,41 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (addr_len < sizeof(struct sockaddr_in))
                goto out;
 
-       s_addr = s_addr1 = addr->sin_addr.s_addr;
+       s_addr = addr->sin_addr.s_addr;
+       s_addr1 = s_addr;
+       s_addr2 = 0xffffffffl;
+
        vxdprintk(VXD_CBIT(net, 3),
-               "inet_bind(%p) %p,%p;%lx",
+               "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d",
                sk, sk->sk_nx_info, sk->sk_socket,
-               (sk->sk_socket?sk->sk_socket->flags:0));
+               (sk->sk_socket?sk->sk_socket->flags:0),
+               VXD_QUAD(s_addr));
        if (nxi) {
                __u32 v4_bcast = nxi->v4_bcast;
                __u32 ipv4root = nxi->ipv4[0];
                int nbipv4 = nxi->nbipv4;
+
                if (s_addr == 0) {
+                       /* bind to any for 1-n */
                        s_addr = ipv4root;
-                       if (nbipv4 > 1)
-                               s_addr1 = 0;
-                       else {
-                               s_addr1 = ipv4root;
-                       }
+                       s_addr1 = (nbipv4 > 1) ? 0 : s_addr;
                        s_addr2 = v4_bcast;
                } else if (s_addr == 0x0100007f) {
-                       s_addr = s_addr1 = ipv4root;
+                       /* rewrite localhost to ipv4root */
+                       s_addr = ipv4root;
+                       s_addr1 = ipv4root;
                } else if (s_addr != v4_bcast) {
-                       int i;
-                       for (i=0; i<nbipv4; i++) {
-                               if (s_addr == nxi->ipv4[i])
-                                       break;
-                       }
-                       if (i == nbipv4) {
+                       /* normal address bind */
+                       if (!addr_in_nx_info(nxi, s_addr))
                                return -EADDRNOTAVAIL;
-                       }
                }
        }
        chk_addr_ret = inet_addr_type(s_addr);
 
+       vxdprintk(VXD_CBIT(net, 3),
+               "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d",
+               sk, VXD_QUAD(s_addr), VXD_QUAD(s_addr1), VXD_QUAD(s_addr2));
+
        /* Not specified by any standard per-se, however it breaks too
         * many applications when removed.  It is unfortunate since
         * allowing applications to make a non-local bind solves
@@ -894,7 +881,7 @@ struct proto_ops inet_dgram_ops = {
        .sendpage =     inet_sendpage,
 };
 
-struct net_proto_family inet_family_ops = {
+static struct net_proto_family inet_family_ops = {
        .family = PF_INET,
        .create = inet_create,
        .owner  = THIS_MODULE,
@@ -1067,24 +1054,29 @@ static int __init inet_init(void)
        struct sk_buff *dummy_skb;
        struct inet_protosw *q;
        struct list_head *r;
+       int rc = -EINVAL;
 
        if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
                printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
-               return -EINVAL;
+               goto out;
+       }
+
+       rc = sk_alloc_slab(&tcp_prot, "tcp_sock");
+       if (rc) {
+               sk_alloc_slab_error(&tcp_prot);
+               goto out;
+       }
+       rc = sk_alloc_slab(&udp_prot, "udp_sock");
+       if (rc) {
+               sk_alloc_slab_error(&udp_prot);
+               goto out_tcp_free_slab;
+       }
+       rc = sk_alloc_slab(&raw_prot, "raw_sock");
+       if (rc) {
+               sk_alloc_slab_error(&raw_prot);
+               goto out_udp_free_slab;
        }
 
-       tcp_sk_cachep = kmem_cache_create("tcp_sock",
-                                         sizeof(struct tcp_sock), 0,
-                                         SLAB_HWCACHE_ALIGN, NULL, NULL);
-       udp_sk_cachep = kmem_cache_create("udp_sock",
-                                         sizeof(struct udp_sock), 0,
-                                         SLAB_HWCACHE_ALIGN, NULL, NULL);
-       raw4_sk_cachep = kmem_cache_create("raw4_sock",
-                                          sizeof(struct raw_sock), 0,
-                                          SLAB_HWCACHE_ALIGN, NULL, NULL);
-       if (!tcp_sk_cachep || !udp_sk_cachep || !raw4_sk_cachep)
-               printk(KERN_CRIT
-                      "inet_init: Can't create protocol sock SLAB caches!\n");
        /*
         *      Tell SOCKET that we are alive... 
         */
@@ -1154,7 +1146,14 @@ static int __init inet_init(void)
 
        ipfrag_init();
 
-       return 0;
+       rc = 0;
+out:
+       return rc;
+out_tcp_free_slab:
+       sk_free_slab(&tcp_prot);
+out_udp_free_slab:
+       sk_free_slab(&udp_prot);
+       goto out;
 }
 
 module_init(inet_init);
@@ -1214,7 +1213,6 @@ EXPORT_SYMBOL(inet_accept);
 EXPORT_SYMBOL(inet_bind);
 EXPORT_SYMBOL(inet_dgram_connect);
 EXPORT_SYMBOL(inet_dgram_ops);
-EXPORT_SYMBOL(inet_family_ops);
 EXPORT_SYMBOL(inet_getname);
 EXPORT_SYMBOL(inet_ioctl);
 EXPORT_SYMBOL(inet_listen);