Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
[sfrench/cifs-2.6.git] / net / ipv4 / devinet.c
index e049da8311b5d79fca7fb14b5af2c21c4f6f12c8..5cdbc102a4187a274106c9ec6a8ad830c11d2bd6 100644 (file)
@@ -140,11 +140,11 @@ void in_dev_finish_destroy(struct in_device *idev)
 #endif
        dev_put(dev);
        if (!idev->dead)
-               printk("Freeing alive in_device %p\n", idev);
-       else {
+               pr_err("Freeing alive in_device %p\n", idev);
+       else
                kfree(idev);
-       }
 }
+EXPORT_SYMBOL(in_dev_finish_destroy);
 
 static struct in_device *inetdev_init(struct net_device *dev)
 {
@@ -159,7 +159,8 @@ static struct in_device *inetdev_init(struct net_device *dev)
                        sizeof(in_dev->cnf));
        in_dev->cnf.sysctl = NULL;
        in_dev->dev = dev;
-       if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
+       in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl);
+       if (!in_dev->arp_parms)
                goto out_kfree;
        if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
                dev_disable_lro(dev);
@@ -405,13 +406,15 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex)
 {
        struct net_device *dev;
        struct in_device *in_dev = NULL;
-       read_lock(&dev_base_lock);
-       dev = __dev_get_by_index(net, ifindex);
+
+       rcu_read_lock();
+       dev = dev_get_by_index_rcu(net, ifindex);
        if (dev)
                in_dev = in_dev_get(dev);
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
        return in_dev;
 }
+EXPORT_SYMBOL(inetdev_by_index);
 
 /* Called only from RTNL semaphored context. No locks. */
 
@@ -557,7 +560,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
  *     Determine a default network mask, based on the IP address.
  */
 
-static __inline__ int inet_abc_len(__be32 addr)
+static inline int inet_abc_len(__be32 addr)
 {
        int rc = -1;    /* Something else, probably a multicast. */
 
@@ -646,13 +649,15 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        rtnl_lock();
 
        ret = -ENODEV;
-       if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL)
+       dev = __dev_get_by_name(net, ifr.ifr_name);
+       if (!dev)
                goto done;
 
        if (colon)
                *colon = ':';
 
-       if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
+       in_dev = __in_dev_get_rtnl(dev);
+       if (in_dev) {
                if (tryaddrmatch) {
                        /* Matthias Andree */
                        /* compare label and address (4.4BSD style) */
@@ -720,7 +725,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 
                if (!ifa) {
                        ret = -ENOBUFS;
-                       if ((ifa = inet_alloc_ifa()) == NULL)
+                       ifa = inet_alloc_ifa();
+                       if (!ifa)
                                break;
                        if (colon)
                                memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
@@ -822,10 +828,10 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
        struct ifreq ifr;
        int done = 0;
 
-       if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
+       if (!in_dev)
                goto out;
 
-       for (; ifa; ifa = ifa->ifa_next) {
+       for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
                if (!buf) {
                        done += sizeof(ifr);
                        continue;
@@ -875,36 +881,33 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
                if (!addr)
                        addr = ifa->ifa_local;
        } endfor_ifa(in_dev);
-no_in_dev:
-       rcu_read_unlock();
 
        if (addr)
-               goto out;
+               goto out_unlock;
+no_in_dev:
 
        /* Not loopback addresses on loopback should be preferred
           in this case. It is importnat that lo is the first interface
           in dev_base list.
         */
-       read_lock(&dev_base_lock);
-       rcu_read_lock();
-       for_each_netdev(net, dev) {
-               if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
+       for_each_netdev_rcu(net, dev) {
+               in_dev = __in_dev_get_rcu(dev);
+               if (!in_dev)
                        continue;
 
                for_primary_ifa(in_dev) {
                        if (ifa->ifa_scope != RT_SCOPE_LINK &&
                            ifa->ifa_scope <= scope) {
                                addr = ifa->ifa_local;
-                               goto out_unlock_both;
+                               goto out_unlock;
                        }
                } endfor_ifa(in_dev);
        }
-out_unlock_both:
-       read_unlock(&dev_base_lock);
+out_unlock:
        rcu_read_unlock();
-out:
        return addr;
 }
+EXPORT_SYMBOL(inet_select_addr);
 
 static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
                              __be32 local, int scope)
@@ -940,7 +943,7 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
                }
        } endfor_ifa(in_dev);
 
-       return same? addr : 0;
+       return same ? addr : 0;
 }
 
 /*
@@ -961,17 +964,16 @@ __be32 inet_confirm_addr(struct in_device *in_dev,
                return confirm_addr_indev(in_dev, dst, local, scope);
 
        net = dev_net(in_dev->dev);
-       read_lock(&dev_base_lock);
        rcu_read_lock();
-       for_each_netdev(net, dev) {
-               if ((in_dev = __in_dev_get_rcu(dev))) {
+       for_each_netdev_rcu(net, dev) {
+               in_dev = __in_dev_get_rcu(dev);
+               if (in_dev) {
                        addr = confirm_addr_indev(in_dev, dst, local, scope);
                        if (addr)
                                break;
                }
        }
        rcu_read_unlock();
-       read_unlock(&dev_base_lock);
 
        return addr;
 }
@@ -984,14 +986,16 @@ int register_inetaddr_notifier(struct notifier_block *nb)
 {
        return blocking_notifier_chain_register(&inetaddr_chain, nb);
 }
+EXPORT_SYMBOL(register_inetaddr_notifier);
 
 int unregister_inetaddr_notifier(struct notifier_block *nb)
 {
        return blocking_notifier_chain_unregister(&inetaddr_chain, nb);
 }
+EXPORT_SYMBOL(unregister_inetaddr_notifier);
 
-/* Rename ifa_labels for a device name change. Make some effort to preserve existing
- * alias numbering and to create unique labels if possible.
+/* Rename ifa_labels for a device name change. Make some effort to preserve
+ * existing alias numbering and to create unique labels if possible.
 */
 static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
 {
@@ -1010,11 +1014,10 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
                        sprintf(old, ":%d", named);
                        dot = old;
                }
-               if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) {
+               if (strlen(dot) + strlen(dev->name) < IFNAMSIZ)
                        strcat(ifa->ifa_label, dot);
-               } else {
+               else
                        strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
-               }
 skip:
                rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
        }
@@ -1061,8 +1064,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
                if (!inetdev_valid_mtu(dev->mtu))
                        break;
                if (dev->flags & IFF_LOOPBACK) {
-                       struct in_ifaddr *ifa;
-                       if ((ifa = inet_alloc_ifa()) != NULL) {
+                       struct in_ifaddr *ifa = inet_alloc_ifa();
+
+                       if (ifa) {
                                ifa->ifa_local =
                                  ifa->ifa_address = htonl(INADDR_LOOPBACK);
                                ifa->ifa_prefixlen = 8;
@@ -1170,38 +1174,54 @@ nla_put_failure:
 static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct net *net = sock_net(skb->sk);
-       int idx, ip_idx;
+       int h, s_h;
+       int idx, s_idx;
+       int ip_idx, s_ip_idx;
        struct net_device *dev;
        struct in_device *in_dev;
        struct in_ifaddr *ifa;
-       int s_ip_idx, s_idx = cb->args[0];
+       struct hlist_head *head;
+       struct hlist_node *node;
 
-       s_ip_idx = ip_idx = cb->args[1];
-       idx = 0;
-       for_each_netdev(net, dev) {
-               if (idx < s_idx)
-                       goto cont;
-               if (idx > s_idx)
-                       s_ip_idx = 0;
-               if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
-                       goto cont;
-
-               for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
-                    ifa = ifa->ifa_next, ip_idx++) {
-                       if (ip_idx < s_ip_idx)
-                               continue;
-                       if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
+       s_h = cb->args[0];
+       s_idx = idx = cb->args[1];
+       s_ip_idx = ip_idx = cb->args[2];
+
+       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+               idx = 0;
+               head = &net->dev_index_head[h];
+               rcu_read_lock();
+               hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
+                       if (idx < s_idx)
+                               goto cont;
+                       if (idx > s_idx)
+                               s_ip_idx = 0;
+                       in_dev = __in_dev_get_rcu(dev);
+                       if (!in_dev)
+                               goto cont;
+
+                       for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
+                            ifa = ifa->ifa_next, ip_idx++) {
+                               if (ip_idx < s_ip_idx)
+                                       continue;
+                               if (inet_fill_ifaddr(skb, ifa,
+                                            NETLINK_CB(cb->skb).pid,
                                             cb->nlh->nlmsg_seq,
-                                            RTM_NEWADDR, NLM_F_MULTI) <= 0)
-                               goto done;
-               }
+                                            RTM_NEWADDR, NLM_F_MULTI) <= 0) {
+                                       rcu_read_unlock();
+                                       goto done;
+                               }
+                       }
 cont:
-               idx++;
+                       idx++;
+               }
+               rcu_read_unlock();
        }
 
 done:
-       cb->args[0] = idx;
-       cb->args[1] = ip_idx;
+       cb->args[0] = h;
+       cb->args[1] = idx;
+       cb->args[2] = ip_idx;
 
        return skb->len;
 }
@@ -1239,18 +1259,18 @@ static void devinet_copy_dflt_conf(struct net *net, int i)
 {
        struct net_device *dev;
 
-       read_lock(&dev_base_lock);
-       for_each_netdev(net, dev) {
+       rcu_read_lock();
+       for_each_netdev_rcu(net, dev) {
                struct in_device *in_dev;
-               rcu_read_lock();
+
                in_dev = __in_dev_get_rcu(dev);
                if (in_dev && !test_bit(i, in_dev->cnf.state))
                        in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i];
-               rcu_read_unlock();
        }
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
+/* called with RTNL locked */
 static void inet_forward_change(struct net *net)
 {
        struct net_device *dev;
@@ -1259,7 +1279,6 @@ static void inet_forward_change(struct net *net)
        IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on;
        IPV4_DEVCONF_DFLT(net, FORWARDING) = on;
 
-       read_lock(&dev_base_lock);
        for_each_netdev(net, dev) {
                struct in_device *in_dev;
                if (on)
@@ -1270,7 +1289,6 @@ static void inet_forward_change(struct net *net)
                        IN_DEV_CONF_SET(in_dev, FORWARDING, on);
                rcu_read_unlock();
        }
-       read_unlock(&dev_base_lock);
 }
 
 static int devinet_conf_proc(ctl_table *ctl, int write,
@@ -1378,6 +1396,7 @@ static struct devinet_sysctl_table {
                DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
                DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
                                        "accept_source_route"),
+               DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
                DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
                DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
                DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
@@ -1512,7 +1531,7 @@ static __net_init int devinet_init_net(struct net *net)
        all = &ipv4_devconf;
        dflt = &ipv4_devconf_dflt;
 
-       if (net != &init_net) {
+       if (!net_eq(net, &init_net)) {
                all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL);
                if (all == NULL)
                        goto err_alloc_all;
@@ -1603,8 +1622,3 @@ void __init devinet_init(void)
        rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
 }
 
-EXPORT_SYMBOL(in_dev_finish_destroy);
-EXPORT_SYMBOL(inet_select_addr);
-EXPORT_SYMBOL(inetdev_by_index);
-EXPORT_SYMBOL(register_inetaddr_notifier);
-EXPORT_SYMBOL(unregister_inetaddr_notifier);