#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
return (struct ipv6_pinfo *)(((u8 *)sk) + offset);
}
-static int inet6_create(struct net *net, struct socket *sock, int protocol)
+static int inet6_create(struct net *net, struct socket *sock, int protocol,
+ int kern)
{
struct inet_sock *inet;
struct ipv6_pinfo *np;
}
err = -EPERM;
- if (answer->capability > 0 && !capable(answer->capability))
+ if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
goto out_rcu_unlock;
sock->ops = answer->ops;
inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk);
np->hop_limit = -1;
- np->mcast_hops = -1;
+ np->mcast_hops = IPV6_DEFAULT_MCASTHOPS;
np->mc_loop = 1;
np->pmtudisc = IPV6_PMTUDISC_WANT;
np->ipv6only = net->ipv6.sysctl.bindv6only;
if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL;
+ rcu_read_lock();
if (addr_type & IPV6_ADDR_LINKLOCAL) {
if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) {
/* Binding to link-local address requires an interface */
if (!sk->sk_bound_dev_if) {
err = -EINVAL;
- goto out;
+ goto out_unlock;
}
- dev = dev_get_by_index(net, sk->sk_bound_dev_if);
+ dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
if (!dev) {
err = -ENODEV;
- goto out;
+ goto out_unlock;
}
}
if (!(addr_type & IPV6_ADDR_MULTICAST)) {
if (!ipv6_chk_addr(net, &addr->sin6_addr,
dev, 0)) {
- if (dev)
- dev_put(dev);
err = -EADDRNOTAVAIL;
- goto out;
+ goto out_unlock;
}
}
- if (dev)
- dev_put(dev);
+ rcu_read_unlock();
}
}
out:
release_sock(sk);
return err;
+out_unlock:
+ rcu_read_unlock();
+ goto out;
}
EXPORT_SYMBOL(inet6_bind);
if ((skb = xchg(&np->pktoptions, NULL)) != NULL)
kfree_skb(skb);
+ if ((skb = xchg(&np->rxpmtu, NULL)) != NULL)
+ kfree_skb(skb);
+
/* Free flowlabels */
fl6_free_socklist(sk);
static int __net_init ipv6_init_mibs(struct net *net)
{
- if (snmp_mib_init((void **)net->mib.udp_stats_in6,
+ if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6,
sizeof (struct udp_mib)) < 0)
return -ENOMEM;
- if (snmp_mib_init((void **)net->mib.udplite_stats_in6,
+ if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6,
sizeof (struct udp_mib)) < 0)
goto err_udplite_mib;
- if (snmp_mib_init((void **)net->mib.ipv6_statistics,
+ if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics,
sizeof(struct ipstats_mib)) < 0)
goto err_ip_mib;
- if (snmp_mib_init((void **)net->mib.icmpv6_statistics,
+ if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics,
sizeof(struct icmpv6_mib)) < 0)
goto err_icmp_mib;
- if (snmp_mib_init((void **)net->mib.icmpv6msg_statistics,
+ if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
sizeof(struct icmpv6msg_mib)) < 0)
goto err_icmpmsg_mib;
return 0;
err_icmpmsg_mib:
- snmp_mib_free((void **)net->mib.icmpv6_statistics);
+ snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics);
err_icmp_mib:
- snmp_mib_free((void **)net->mib.ipv6_statistics);
+ snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);
err_ip_mib:
- snmp_mib_free((void **)net->mib.udplite_stats_in6);
+ snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);
err_udplite_mib:
- snmp_mib_free((void **)net->mib.udp_stats_in6);
+ snmp_mib_free((void __percpu **)net->mib.udp_stats_in6);
return -ENOMEM;
}
-static void __net_exit ipv6_cleanup_mibs(struct net *net)
+static void ipv6_cleanup_mibs(struct net *net)
{
- snmp_mib_free((void **)net->mib.udp_stats_in6);
- snmp_mib_free((void **)net->mib.udplite_stats_in6);
- snmp_mib_free((void **)net->mib.ipv6_statistics);
- snmp_mib_free((void **)net->mib.icmpv6_statistics);
- snmp_mib_free((void **)net->mib.icmpv6msg_statistics);
+ snmp_mib_free((void __percpu **)net->mib.udp_stats_in6);
+ snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);
+ snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);
+ snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics);
+ snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics);
}
static int __net_init inet6_net_init(struct net *net)
#endif
}
-static void inet6_net_exit(struct net *net)
+static void __net_exit inet6_net_exit(struct net *net)
{
#ifdef CONFIG_PROC_FS
udp6_proc_exit(net);