static void inet6_prefix_notify(int event, struct inet6_dev *idev,
struct prefix_info *pinfo);
-static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev);
+static int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
+ struct net_device *dev);
static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
rwlock_init(&ndev->lock);
ndev->dev = dev;
- memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
+ memcpy(&ndev->cnf, dev->nd_net->ipv6.devconf_dflt, sizeof(ndev->cnf));
ndev->cnf.mtu6 = dev->mtu;
ndev->cnf.sysctl = NULL;
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
}
-static void addrconf_forward_change(struct net *net)
+static void addrconf_forward_change(struct net *net, __s32 newf)
{
struct net_device *dev;
struct inet6_dev *idev;
rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev) {
- int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding);
- idev->cnf.forwarding = ipv6_devconf.forwarding;
+ int changed = (!idev->cnf.forwarding) ^ (!newf);
+ idev->cnf.forwarding = newf;
if (changed)
dev_forward_change(idev);
}
struct net *net;
net = (struct net *)table->extra2;
- if (p == &ipv6_devconf_dflt.forwarding)
+ if (p == &net->ipv6.devconf_dflt->forwarding)
return;
- if (p == &ipv6_devconf.forwarding) {
- ipv6_devconf_dflt.forwarding = ipv6_devconf.forwarding;
- addrconf_forward_change(net);
+ if (p == &net->ipv6.devconf_all->forwarding) {
+ __s32 newf = net->ipv6.devconf_all->forwarding;
+ net->ipv6.devconf_dflt->forwarding = newf;
+ addrconf_forward_change(net, newf);
} else if ((!*p) ^ (!old))
dev_forward_change((struct inet6_dev *)table->extra1);
write_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */
- if (ipv6_chk_same_addr(addr, idev->dev)) {
+ if (ipv6_chk_same_addr(&init_net, addr, idev->dev)) {
ADBG(("ipv6_add_addr: already assigned\n"));
err = -EEXIST;
goto out;
if (hiscore.rule < 7)
hiscore.rule++;
#endif
+
+ /* Skip rule 8 for orchid -> non-orchid address pairs. */
+ if (ipv6_addr_orchid(&ifa->addr) && !ipv6_addr_orchid(daddr))
+ continue;
+
/* Rule 8: Use longest matching prefix */
if (hiscore.rule < 8) {
hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
return cnt;
}
-int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict)
+int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
+ struct net_device *dev, int strict)
{
struct inet6_ifaddr * ifp;
u8 hash = ipv6_addr_hash(addr);
read_lock_bh(&addrconf_hash_lock);
for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ if (ifp->idev->dev->nd_net != net)
+ continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
!(ifp->flags&IFA_F_TENTATIVE)) {
if (dev == NULL || ifp->idev->dev == dev ||
read_unlock_bh(&addrconf_hash_lock);
return ifp != NULL;
}
-
EXPORT_SYMBOL(ipv6_chk_addr);
static
-int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
+int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
+ struct net_device *dev)
{
struct inet6_ifaddr * ifp;
u8 hash = ipv6_addr_hash(addr);
for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ if (ifp->idev->dev->nd_net != net)
+ continue;
if (ipv6_addr_equal(&ifp->addr, addr)) {
if (dev == NULL || ifp->idev->dev == dev)
break;
return ifp != NULL;
}
-struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev, int strict)
+struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr,
+ struct net_device *dev, int strict)
{
struct inet6_ifaddr * ifp;
u8 hash = ipv6_addr_hash(addr);
read_lock_bh(&addrconf_hash_lock);
for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ if (ifp->idev->dev->nd_net != net)
+ continue;
if (ipv6_addr_equal(&ifp->addr, addr)) {
if (dev == NULL || ifp->idev->dev == dev ||
!(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) {
.fc_expires = expires,
.fc_dst_len = plen,
.fc_flags = RTF_UP | flags,
+ .fc_nlinfo.nl_net = &init_net,
};
ipv6_addr_copy(&cfg.fc_dst, pfx);
.fc_ifindex = dev->ifindex,
.fc_dst_len = 8,
.fc_flags = RTF_UP,
+ .fc_nlinfo.nl_net = &init_net,
};
ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
.fc_ifindex = dev->ifindex,
.fc_dst_len = 96,
.fc_flags = RTF_UP | RTF_NONEXTHOP,
+ .fc_nlinfo.nl_net = &init_net,
};
/* prefix length - 96 bits "::d.d.d.d" */
ok:
- ifp = ipv6_get_ifaddr(&addr, dev, 1);
+ ifp = ipv6_get_ifaddr(&init_net, &addr, dev, 1);
if (ifp == NULL && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
p.iph.ihl = 5;
p.iph.protocol = IPPROTO_IPV6;
p.iph.ttl = 64;
- ifr.ifr_ifru.ifru_data = (void __user *)&p;
+ ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
oldfs = get_fs(); set_fs(KERNEL_DS);
err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
#ifdef CONFIG_PROC_FS
struct if6_iter_state {
+ struct seq_net_private p;
int bucket;
};
{
struct inet6_ifaddr *ifa = NULL;
struct if6_iter_state *state = seq->private;
+ struct net *net = state->p.net;
for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
ifa = inet6_addr_lst[state->bucket];
+
+ while (ifa && ifa->idev->dev->nd_net != net)
+ ifa = ifa->lst_next;
if (ifa)
break;
}
static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa)
{
struct if6_iter_state *state = seq->private;
+ struct net *net = state->p.net;
ifa = ifa->lst_next;
try_again:
+ if (ifa) {
+ if (ifa->idev->dev->nd_net != net) {
+ ifa = ifa->lst_next;
+ goto try_again;
+ }
+ }
+
if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) {
ifa = inet6_addr_lst[state->bucket];
goto try_again;
}
+
return ifa;
}
}
static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(addrconf_hash_lock)
{
read_lock_bh(&addrconf_hash_lock);
return if6_get_idx(seq, *pos);
}
static void if6_seq_stop(struct seq_file *seq, void *v)
+ __releases(addrconf_hash_lock)
{
read_unlock_bh(&addrconf_hash_lock);
}
static int if6_seq_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &if6_seq_ops,
- sizeof(struct if6_iter_state));
+ return seq_open_net(inode, file, &if6_seq_ops,
+ sizeof(struct if6_iter_state));
}
static const struct file_operations if6_fops = {
.open = if6_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
-int __init if6_proc_init(void)
+static int if6_proc_net_init(struct net *net)
{
- if (!proc_net_fops_create(&init_net, "if_inet6", S_IRUGO, &if6_fops))
+ if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops))
return -ENOMEM;
return 0;
}
+static void if6_proc_net_exit(struct net *net)
+{
+ proc_net_remove(net, "if_inet6");
+}
+
+static struct pernet_operations if6_proc_net_ops = {
+ .init = if6_proc_net_init,
+ .exit = if6_proc_net_exit,
+};
+
+int __init if6_proc_init(void)
+{
+ return register_pernet_subsys(&if6_proc_net_ops);
+}
+
void if6_proc_exit(void)
{
- proc_net_remove(&init_net, "if_inet6");
+ unregister_pernet_subsys(&if6_proc_net_ops);
}
#endif /* CONFIG_PROC_FS */
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
/* Check if address is a home address configured on any interface. */
-int ipv6_chk_home_addr(struct in6_addr *addr)
+int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
{
int ret = 0;
struct inet6_ifaddr * ifp;
u8 hash = ipv6_addr_hash(addr);
read_lock_bh(&addrconf_hash_lock);
for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
+ if (ifp->idev->dev->nd_net != net)
+ continue;
if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&
(ifp->flags & IFA_F_HOMEADDRESS)) {
ret = 1;
/* We ignore other flags so far. */
ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
- ifa = ipv6_get_ifaddr(pfx, dev, 1);
+ ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
if (ifa == NULL) {
/*
* It would be best to check for !NLM_F_CREATE here but
ifa = ifa->if_next, ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
- if ((err = inet6_fill_ifaddr(skb, ifa,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, RTM_NEWADDR,
- NLM_F_MULTI)) <= 0)
- goto done;
+ err = inet6_fill_ifaddr(skb, ifa,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWADDR,
+ NLM_F_MULTI);
}
break;
case MULTICAST_ADDR:
ifmca = ifmca->next, ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
- if ((err = inet6_fill_ifmcaddr(skb, ifmca,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, RTM_GETMULTICAST,
- NLM_F_MULTI)) <= 0)
- goto done;
+ err = inet6_fill_ifmcaddr(skb, ifmca,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_GETMULTICAST,
+ NLM_F_MULTI);
}
break;
case ANYCAST_ADDR:
ifaca = ifaca->aca_next, ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
- if ((err = inet6_fill_ifacaddr(skb, ifaca,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, RTM_GETANYCAST,
- NLM_F_MULTI)) <= 0)
- goto done;
+ err = inet6_fill_ifacaddr(skb, ifaca,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_GETANYCAST,
+ NLM_F_MULTI);
}
break;
default:
}
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
+
+ if (err <= 0)
+ break;
cont:
idx++;
}
-done:
- if (err <= 0) {
- read_unlock_bh(&idev->lock);
- in6_dev_put(idev);
- }
cb->args[0] = idx;
cb->args[1] = ip_idx;
return skb->len;
if (ifm->ifa_index)
dev = __dev_get_by_index(&init_net, ifm->ifa_index);
- if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) {
+ if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
err = -EADDRNOTAVAIL;
goto errout;
}