X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv4%2Faf_inet.c;h=24eca23c2db3159c91898bd7fefe8bbb501f1233;hb=aca51397d01474f80cab8fc978559b45f2e453ad;hp=a9e241cdc5b2542bb527e24c9d0a7b244ff19de0;hpb=05cf89d40c85e622dac20e44713168767be5c520;p=linux-2.6 diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a9e241cdc5..24eca23c2d 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -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(sk->sk_net, addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -784,7 +802,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); switch (cmd) { case SIOCGSTAMP: @@ -1059,7 +1077,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) if (sysctl_ip_dynaddr > 1) { printk(KERN_INFO "%s(): shifting inet->" - "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n", + "saddr from " NIPQUAD_FMT " to " NIPQUAD_FMT "\n", __func__, NIPQUAD(old_saddr), NIPQUAD(new_saddr)); @@ -1114,7 +1132,7 @@ int inet_sk_rebuild_header(struct sock *sk) }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0); } if (!err) sk_setup_caps(sk, &rt->u.dst); @@ -1216,7 +1234,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) segs = ops->gso_segment(skb, features); rcu_read_unlock(); - if (!segs || unlikely(IS_ERR(segs))) + if (!segs || IS_ERR(segs)) goto out; skb = segs; @@ -1232,6 +1250,29 @@ out: return segs; } +int inet_ctl_sock_create(struct sock **sk, unsigned short family, + unsigned short type, unsigned char protocol, + struct net *net) +{ + struct socket *sock; + int rc = sock_create_kern(family, type, protocol, &sock); + + if (rc == 0) { + *sk = sock->sk; + (*sk)->sk_allocation = GFP_ATOMIC; + /* + * Unhash it so that IP input processing does not even see it, + * we do not wish this socket to see incoming packets. + */ + (*sk)->sk_prot->unhash(*sk); + + sk_change_net(*sk, net); + } + return rc; +} + +EXPORT_SYMBOL_GPL(inet_ctl_sock_create); + unsigned long snmp_fold_field(void *mib[], int offt) { unsigned long res = 0; @@ -1284,17 +1325,20 @@ static struct net_protocol tcp_protocol = { .gso_send_check = tcp_v4_gso_send_check, .gso_segment = tcp_tso_segment, .no_policy = 1, + .netns_ok = 1, }; static struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, .no_policy = 1, + .netns_ok = 1, }; static struct net_protocol icmp_protocol = { .handler = icmp_rcv, .no_policy = 1, + .netns_ok = 1, }; static int __init init_ipv4_mibs(void)