]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv6/addrconf.c
osk: use gpiolib with tps65010
[linux-2.6-omap-h63xx.git] / net / ipv6 / addrconf.c
index 9b96de3ba5eb334f649040f8e6a8ca16968fc827..e40213db9e4c6355e665c8684e4549feca77614d 100644 (file)
@@ -149,7 +149,8 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
 
 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);
 
@@ -456,7 +457,7 @@ static void dev_forward_change(struct inet6_dev *idev)
 }
 
 
-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;
@@ -466,8 +467,8 @@ static void addrconf_forward_change(struct net *net)
                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);
                }
@@ -484,9 +485,10 @@ static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
        if (p == &net->ipv6.devconf_dflt->forwarding)
                return;
 
-       if (p == &ipv6_devconf.forwarding) {
-               net->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);
 
@@ -559,7 +561,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        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;
@@ -1205,13 +1207,16 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
        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 ||
@@ -1222,16 +1227,18 @@ int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev, int strict)
        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;
@@ -1240,13 +1247,16 @@ int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
        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)) {
@@ -1732,7 +1742,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 
 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;
@@ -1890,7 +1900,7 @@ int addrconf_set_dstaddr(void __user *arg)
                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);
@@ -2735,6 +2745,7 @@ static void addrconf_dad_run(struct inet6_dev *idev) {
 
 #ifdef CONFIG_PROC_FS
 struct if6_iter_state {
+       struct seq_net_private p;
        int bucket;
 };
 
@@ -2742,9 +2753,13 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
 {
        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;
        }
@@ -2754,13 +2769,22 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
 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;
 }
 
@@ -2775,6 +2799,7 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 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);
@@ -2790,6 +2815,7 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void if6_seq_stop(struct seq_file *seq, void *v)
+       __releases(addrconf_hash_lock)
 {
        read_unlock_bh(&addrconf_hash_lock);
 }
@@ -2817,8 +2843,8 @@ static const struct seq_operations if6_seq_ops = {
 
 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 = {
@@ -2826,31 +2852,48 @@ 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;
@@ -3099,7 +3142,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        /* 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
@@ -3292,11 +3335,11 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                             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:
@@ -3305,11 +3348,11 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                             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:
@@ -3318,11 +3361,11 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                             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:
@@ -3330,14 +3373,12 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                }
                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;
@@ -3406,7 +3447,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
        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;
        }