]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv4/af_inet.c
[NETNS]: Allow to create sockets in non-initial namespace.
[linux-2.6-omap-h63xx.git] / net / ipv4 / af_inet.c
index 4cb8a1385539e3a82123f4c6c3e32a852570f312..39ddb84b1b783b2b9d2aca2bf18681dee52325af 100644 (file)
@@ -243,6 +243,23 @@ void build_ehash_secret(void)
 }
 EXPORT_SYMBOL(build_ehash_secret);
 
+static inline int inet_netns_ok(struct net *net, int protocol)
+{
+       int hash;
+       struct net_protocol *ipprot;
+
+       if (net == &init_net)
+               return 1;
+
+       hash = protocol & (MAX_INET_PROTOS - 1);
+       ipprot = rcu_dereference(inet_protos[hash]);
+
+       if (ipprot == NULL)
+               /* raw IP is OK */
+               return 1;
+       return ipprot->netns_ok;
+}
+
 /*
  *     Create an inet socket.
  */
@@ -259,9 +276,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol)
        int try_loading_module = 0;
        int err;
 
-       if (net != &init_net)
-               return -EAFNOSUPPORT;
-
        if (sock->type != SOCK_RAW &&
            sock->type != SOCK_DGRAM &&
            !inet_ehash_secret)
@@ -320,6 +334,10 @@ lookup_protocol:
        if (answer->capability > 0 && !capable(answer->capability))
                goto out_rcu_unlock;
 
+       err = -EAFNOSUPPORT;
+       if (!inet_netns_ok(net, protocol))
+               goto out_rcu_unlock;
+
        sock->ops = answer->ops;
        answer_prot = answer->prot;
        answer_no_check = answer->no_check;
@@ -446,7 +464,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (addr_len < sizeof(struct sockaddr_in))
                goto out;
 
-       chk_addr_ret = inet_addr_type(&init_net, addr->sin_addr.s_addr);
+       chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr);
 
        /* Not specified by any standard per-se, however it breaks too
         * many applications when removed.  It is unfortunate since
@@ -458,7 +476,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        err = -EADDRNOTAVAIL;
        if (!sysctl_ip_nonlocal_bind &&
            !inet->freebind &&
-           addr->sin_addr.s_addr != INADDR_ANY &&
+           addr->sin_addr.s_addr != htonl(INADDR_ANY) &&
            chk_addr_ret != RTN_LOCAL &&
            chk_addr_ret != RTN_MULTICAST &&
            chk_addr_ret != RTN_BROADCAST)
@@ -1114,7 +1132,7 @@ int inet_sk_rebuild_header(struct sock *sk)
        };
 
        security_sk_classify_flow(sk, &fl);
-       err = ip_route_output_flow(&init_net, &rt, &fl, sk, 0);
+       err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0);
 }
        if (!err)
                sk_setup_caps(sk, &rt->u.dst);