atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated);
-static inline int __udp_lib_lport_inuse(__u16 num,
+static inline int __udp_lib_lport_inuse(struct net *net, __u16 num,
const struct hlist_head udptable[])
{
struct sock *sk;
struct hlist_node *node;
sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
- if (sk->sk_hash == num)
+ if (sock_net(sk) == net && sk->sk_hash == num)
return 1;
return 0;
}
/**
- * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6
+ * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6
*
* @sk: socket struct in question
* @snum: port number to look up
- * @udptable: hash list table, must be of UDP_HTABLE_SIZE
* @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 udp_lib_get_port(struct sock *sk, unsigned short snum,
int (*saddr_comp)(const struct sock *sk1,
const struct sock *sk2 ) )
{
+ struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
struct hlist_node *node;
struct hlist_head *head;
struct sock *sk2;
int error = 1;
+ struct net *net = sock_net(sk);
write_lock_bh(&udp_hash_lock);
/* 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))
+ if (! __udp_lib_lport_inuse(net, rover, udptable))
goto gotit;
rover += UDP_HTABLE_SIZE;
if (rover > high)
sk_for_each(sk2, node, head)
if (sk2->sk_hash == snum &&
sk2 != sk &&
+ sock_net(sk2) == net &&
(!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
return error;
}
-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, scmp);
-}
-
-int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
{
struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
inet1->rcv_saddr == inet2->rcv_saddr ));
}
-static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
+int udp_v4_get_port(struct sock *sk, unsigned short snum)
{
- return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
+ return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal);
}
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
* harder than this. -DaveM
*/
-static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
- __be32 daddr, __be16 dport,
- int dif, struct hlist_head udptable[])
+static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
+ __be16 sport, __be32 daddr, __be16 dport,
+ int dif, struct hlist_head udptable[])
{
struct sock *sk, *result = NULL;
struct hlist_node *node;
sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
struct inet_sock *inet = inet_sk(sk);
- if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) {
+ if (sock_net(sk) == net && sk->sk_hash == hnum &&
+ !ipv6_only_sock(sk)) {
int score = (sk->sk_family == PF_INET ? 1 : 0);
if (inet->rcv_saddr) {
if (inet->rcv_saddr != daddr)
int harderr;
int err;
- sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source,
- skb->dev->ifindex, udptable );
+ sk = __udp4_lib_lookup(dev_net(skb->dev), iph->daddr, uh->dest,
+ iph->saddr, uh->source, skb->dev->ifindex, udptable);
if (sk == NULL) {
ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
return; /* No socket for error */
ipc.oif = sk->sk_bound_dev_if;
if (msg->msg_controllen) {
- err = ip_cmsg_send(msg, &ipc);
+ err = ip_cmsg_send(sock_net(sk), msg, &ipc);
if (err)
return err;
if (ipc.opt)
{ .sport = inet->sport,
.dport = dport } } };
security_sk_classify_flow(sk, &fl);
- err = ip_route_output_flow(&rt, &fl, sk, 1);
+ err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1);
if (err) {
if (err == -ENETUNREACH)
IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
- sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
- inet_iif(skb), udptable);
+ sk = __udp4_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr,
+ uh->dest, inet_iif(skb), udptable);
if (sk != NULL) {
int ret = 0;
.sysctl_wmem = &sysctl_udp_wmem_min,
.sysctl_rmem = &sysctl_udp_rmem_min,
.obj_size = sizeof(struct udp_sock),
+ .h.udp_hash = udp_hash,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_udp_setsockopt,
.compat_getsockopt = compat_udp_getsockopt,
{
struct sock *sk;
struct udp_iter_state *state = seq->private;
+ struct net *net = state->net;
for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
struct hlist_node *node;
sk_for_each(sk, node, state->hashtable + state->bucket) {
+ if (sock_net(sk) != net)
+ continue;
if (sk->sk_family == state->family)
goto found;
}
static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
{
struct udp_iter_state *state = seq->private;
+ struct net *net = state->net;
do {
sk = sk_next(sk);
try_again:
;
- } while (sk && sk->sk_family != state->family);
+ } while (sk && (sock_net(sk) != net || sk->sk_family != state->family));
if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
sk = sk_head(state->hashtable + state->bucket);
{
struct udp_seq_afinfo *afinfo = PDE(inode)->data;
struct seq_file *seq;
+ struct net *net;
int rc = -ENOMEM;
struct udp_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
+
+ rc = -ENXIO;
+ net = get_proc_net(inode);
+ if (!net)
+ goto out_kfree;
+
s->family = afinfo->family;
s->hashtable = afinfo->hashtable;
s->seq_ops.start = udp_seq_start;
s->seq_ops.next = udp_seq_next;
s->seq_ops.show = afinfo->seq_show;
s->seq_ops.stop = udp_seq_stop;
+ s->net = net;
rc = seq_open(file, &s->seq_ops);
if (rc)
- goto out_kfree;
+ goto out_put_net;
- seq = file->private_data;
+ seq = file->private_data;
seq->private = s;
out:
return rc;
+out_put_net:
+ put_net(net);
out_kfree:
kfree(s);
goto out;
}
+static int udp_seq_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct udp_iter_state *s = seq->private;
+
+ put_net(s->net);
+ seq_release_private(inode, file);
+ return 0;
+}
+
/* ------------------------------------------------------------------------ */
-int udp_proc_register(struct udp_seq_afinfo *afinfo)
+int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo)
{
struct proc_dir_entry *p;
int rc = 0;
afinfo->seq_fops->open = udp_seq_open;
afinfo->seq_fops->read = seq_read;
afinfo->seq_fops->llseek = seq_lseek;
- afinfo->seq_fops->release = seq_release_private;
+ afinfo->seq_fops->release = udp_seq_release;
- p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);
+ p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops);
if (p)
p->data = afinfo;
else
return rc;
}
-void udp_proc_unregister(struct udp_seq_afinfo *afinfo)
+void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo)
{
if (!afinfo)
return;
- proc_net_remove(&init_net, afinfo->name);
+ proc_net_remove(net, afinfo->name);
memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
}
.seq_fops = &udp4_seq_fops,
};
+static int udp4_proc_init_net(struct net *net)
+{
+ return udp_proc_register(net, &udp4_seq_afinfo);
+}
+
+static void udp4_proc_exit_net(struct net *net)
+{
+ udp_proc_unregister(net, &udp4_seq_afinfo);
+}
+
+static struct pernet_operations udp4_net_ops = {
+ .init = udp4_proc_init_net,
+ .exit = udp4_proc_exit_net,
+};
+
int __init udp4_proc_init(void)
{
- return udp_proc_register(&udp4_seq_afinfo);
+ return register_pernet_subsys(&udp4_net_ops);
}
void udp4_proc_exit(void)
{
- udp_proc_unregister(&udp4_seq_afinfo);
+ unregister_pernet_subsys(&udp4_net_ops);
}
#endif /* CONFIG_PROC_FS */
EXPORT_SYMBOL(udp_hash);
EXPORT_SYMBOL(udp_hash_lock);
EXPORT_SYMBOL(udp_ioctl);
-EXPORT_SYMBOL(udp_get_port);
EXPORT_SYMBOL(udp_prot);
EXPORT_SYMBOL(udp_sendmsg);
EXPORT_SYMBOL(udp_lib_getsockopt);
EXPORT_SYMBOL(udp_lib_setsockopt);
EXPORT_SYMBOL(udp_poll);
+EXPORT_SYMBOL(udp_lib_get_port);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(udp_proc_register);