]> err.no Git - linux-2.6/blobdiff - net/core/neighbour.c
cfg80211/nl80211: add beacon settings
[linux-2.6] / net / core / neighbour.c
index 67ba9914e52e78aadb1f0be6cde6fc0219c8c544..9a283fcde9a631bad5f5863137165cb9b28634e5 100644 (file)
@@ -165,6 +165,16 @@ static int neigh_forced_gc(struct neigh_table *tbl)
        return shrunk;
 }
 
+static void neigh_add_timer(struct neighbour *n, unsigned long when)
+{
+       neigh_hold(n);
+       if (unlikely(mod_timer(&n->timer, when))) {
+               printk("NEIGH: BUG, double timer add, state is %x\n",
+                      n->nud_state);
+               dump_stack();
+       }
+}
+
 static int neigh_del_timer(struct neighbour *n)
 {
        if ((n->nud_state & NUD_IN_TIMER) &&
@@ -270,9 +280,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
        n->nud_state      = NUD_NONE;
        n->output         = neigh_blackhole;
        n->parms          = neigh_parms_clone(&tbl->parms);
-       init_timer(&n->timer);
-       n->timer.function = neigh_timer_handler;
-       n->timer.data     = (unsigned long)n;
+       setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
 
        NEIGH_CACHE_STAT_INC(tbl, allocs);
        n->tbl            = tbl;
@@ -718,15 +726,6 @@ static __inline__ int neigh_max_probes(struct neighbour *n)
                p->ucast_probes + p->app_probes + p->mcast_probes);
 }
 
-static inline void neigh_add_timer(struct neighbour *n, unsigned long when)
-{
-       if (unlikely(mod_timer(&n->timer, when))) {
-               printk("NEIGH: BUG, double timer add, state is %x\n",
-                      n->nud_state);
-               dump_stack();
-       }
-}
-
 /* Called when a timer expires for a neighbour entry. */
 
 static void neigh_timer_handler(unsigned long arg)
@@ -858,7 +857,6 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        atomic_set(&neigh->probes, neigh->parms->ucast_probes);
                        neigh->nud_state     = NUD_INCOMPLETE;
                        neigh->updated = jiffies;
-                       neigh_hold(neigh);
                        neigh_add_timer(neigh, now + 1);
                } else {
                        neigh->nud_state = NUD_FAILED;
@@ -871,7 +869,6 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                }
        } else if (neigh->nud_state & NUD_STALE) {
                NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
-               neigh_hold(neigh);
                neigh->nud_state = NUD_DELAY;
                neigh->updated = jiffies;
                neigh_add_timer(neigh,
@@ -1015,13 +1012,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
 
        if (new != old) {
                neigh_del_timer(neigh);
-               if (new & NUD_IN_TIMER) {
-                       neigh_hold(neigh);
+               if (new & NUD_IN_TIMER)
                        neigh_add_timer(neigh, (jiffies +
                                                ((new & NUD_REACHABLE) ?
                                                 neigh->parms->reachable_time :
                                                 0)));
-               }
                neigh->nud_state = new;
        }
 
@@ -1372,15 +1367,11 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
        get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
 
        rwlock_init(&tbl->lock);
-       init_timer(&tbl->gc_timer);
-       tbl->gc_timer.data     = (unsigned long)tbl;
-       tbl->gc_timer.function = neigh_periodic_timer;
+       setup_timer(&tbl->gc_timer, neigh_periodic_timer, (unsigned long)tbl);
        tbl->gc_timer.expires  = now + 1;
        add_timer(&tbl->gc_timer);
 
-       init_timer(&tbl->proxy_timer);
-       tbl->proxy_timer.data     = (unsigned long)tbl;
-       tbl->proxy_timer.function = neigh_proxy_process;
+       setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
        skb_queue_head_init_class(&tbl->proxy_queue,
                        &neigh_table_proxy_queue_class);
 
@@ -1435,9 +1426,14 @@ int neigh_table_clear(struct neigh_table *tbl)
        kfree(tbl->phash_buckets);
        tbl->phash_buckets = NULL;
 
+       remove_proc_entry(tbl->id, init_net.proc_net_stat);
+
        free_percpu(tbl->stats);
        tbl->stats = NULL;
 
+       kmem_cache_destroy(tbl->kmem_cachep);
+       tbl->kmem_cachep = NULL;
+
        return 0;
 }
 
@@ -1450,6 +1446,9 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct net_device *dev = NULL;
        int err = -EINVAL;
 
+       if (net != &init_net)
+               return -EINVAL;
+
        if (nlmsg_len(nlh) < sizeof(*ndm))
                goto out;
 
@@ -1516,6 +1515,9 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct net_device *dev = NULL;
        int err;
 
+       if (net != &init_net)
+               return -EINVAL;
+
        err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
        if (err < 0)
                goto out;
@@ -1790,11 +1792,15 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
 
 static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct neigh_table *tbl;
        struct ndtmsg *ndtmsg;
        struct nlattr *tb[NDTA_MAX+1];
        int err;
 
+       if (net != &init_net)
+               return -EINVAL;
+
        err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
                          nl_neightbl_policy);
        if (err < 0)
@@ -1914,11 +1920,15 @@ errout:
 
 static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        int family, tidx, nidx = 0;
        int tbl_skip = cb->args[0];
        int neigh_skip = cb->args[1];
        struct neigh_table *tbl;
 
+       if (net != &init_net)
+               return 0;
+
        family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
 
        read_lock(&neigh_tbl_lock);
@@ -2043,9 +2053,13 @@ out:
 
 static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        struct neigh_table *tbl;
        int t, family, s_t;
 
+       if (net != &init_net)
+               return 0;
+
        read_lock(&neigh_tbl_lock);
        family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
        s_t = cb->args[0];
@@ -2450,10 +2464,10 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(RTNLGRP_NEIGH, err);
+               rtnl_set_sk_err(&init_net, RTNLGRP_NEIGH, err);
 }
 
 #ifdef CONFIG_ARPD
@@ -2467,11 +2481,8 @@ void neigh_app_ns(struct neighbour *n)
 
 static struct neigh_sysctl_table {
        struct ctl_table_header *sysctl_header;
-       ctl_table               neigh_vars[__NET_NEIGH_MAX];
-       ctl_table               neigh_dev[2];
-       ctl_table               neigh_neigh_dir[2];
-       ctl_table               neigh_proto_dir[2];
-       ctl_table               neigh_root_dir[2];
+       struct ctl_table neigh_vars[__NET_NEIGH_MAX];
+       char *dev_name;
 } neigh_sysctl_template __read_mostly = {
        .neigh_vars = {
                {
@@ -2602,32 +2613,7 @@ static struct neigh_sysctl_table {
                        .mode           = 0644,
                        .proc_handler   = &proc_dointvec,
                },
-               {}
-       },
-       .neigh_dev = {
-               {
-                       .ctl_name       = NET_PROTO_CONF_DEFAULT,
-                       .procname       = "default",
-                       .mode           = 0555,
-               },
-       },
-       .neigh_neigh_dir = {
-               {
-                       .procname       = "neigh",
-                       .mode           = 0555,
-               },
-       },
-       .neigh_proto_dir = {
-               {
-                       .mode           = 0555,
-               },
-       },
-       .neigh_root_dir = {
-               {
-                       .ctl_name       = CTL_NET,
-                       .procname       = "net",
-                       .mode           = 0555,
-               },
+               {},
        },
 };
 
@@ -2635,14 +2621,26 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
                          int p_id, int pdev_id, char *p_name,
                          proc_handler *handler, ctl_handler *strategy)
 {
-       struct neigh_sysctl_table *t = kmemdup(&neigh_sysctl_template,
-                                              sizeof(*t), GFP_KERNEL);
+       struct neigh_sysctl_table *t;
        const char *dev_name_source = NULL;
-       char *dev_name = NULL;
-       int err = 0;
 
+#define NEIGH_CTL_PATH_ROOT    0
+#define NEIGH_CTL_PATH_PROTO   1
+#define NEIGH_CTL_PATH_NEIGH   2
+#define NEIGH_CTL_PATH_DEV     3
+
+       struct ctl_path neigh_path[] = {
+               { .procname = "net",     .ctl_name = CTL_NET, },
+               { .procname = "proto",   .ctl_name = 0, },
+               { .procname = "neigh",   .ctl_name = 0, },
+               { .procname = "default", .ctl_name = NET_PROTO_CONF_DEFAULT, },
+               { },
+       };
+
+       t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
        if (!t)
-               return -ENOBUFS;
+               goto err;
+
        t->neigh_vars[0].data  = &p->mcast_probes;
        t->neigh_vars[1].data  = &p->ucast_probes;
        t->neigh_vars[2].data  = &p->app_probes;
@@ -2660,11 +2658,11 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
 
        if (dev) {
                dev_name_source = dev->name;
-               t->neigh_dev[0].ctl_name = dev->ifindex;
+               neigh_path[NEIGH_CTL_PATH_DEV].ctl_name = dev->ifindex;
                /* Terminate the table early */
                memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
        } else {
-               dev_name_source = t->neigh_dev[0].procname;
+               dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
                t->neigh_vars[14].data = (int *)(p + 1);
                t->neigh_vars[15].data = (int *)(p + 1) + 1;
                t->neigh_vars[16].data = (int *)(p + 1) + 2;
@@ -2699,39 +2697,28 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
                        t->neigh_vars[13].ctl_name = CTL_UNNUMBERED;
        }
 
-       dev_name = kstrdup(dev_name_source, GFP_KERNEL);
-       if (!dev_name) {
-               err = -ENOBUFS;
+       t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
+       if (!t->dev_name)
                goto free;
-       }
 
-       t->neigh_dev[0].procname = dev_name;
+       neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
+       neigh_path[NEIGH_CTL_PATH_NEIGH].ctl_name = pdev_id;
+       neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
+       neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id;
 
-       t->neigh_neigh_dir[0].ctl_name = pdev_id;
-
-       t->neigh_proto_dir[0].procname = p_name;
-       t->neigh_proto_dir[0].ctl_name = p_id;
-
-       t->neigh_dev[0].child          = t->neigh_vars;
-       t->neigh_neigh_dir[0].child    = t->neigh_dev;
-       t->neigh_proto_dir[0].child    = t->neigh_neigh_dir;
-       t->neigh_root_dir[0].child     = t->neigh_proto_dir;
-
-       t->sysctl_header = register_sysctl_table(t->neigh_root_dir);
-       if (!t->sysctl_header) {
-               err = -ENOBUFS;
+       t->sysctl_header = register_sysctl_paths(neigh_path, t->neigh_vars);
+       if (!t->sysctl_header)
                goto free_procname;
-       }
+
        p->sysctl_table = t;
        return 0;
 
-       /* error path */
- free_procname:
-       kfree(dev_name);
- free:
+free_procname:
+       kfree(t->dev_name);
+free:
        kfree(t);
-
-       return err;
+err:
+       return -ENOBUFS;
 }
 
 void neigh_sysctl_unregister(struct neigh_parms *p)
@@ -2740,7 +2727,7 @@ void neigh_sysctl_unregister(struct neigh_parms *p)
                struct neigh_sysctl_table *t = p->sysctl_table;
                p->sysctl_table = NULL;
                unregister_sysctl_table(t->sysctl_header);
-               kfree(t->neigh_dev[0].procname);
+               kfree(t->dev_name);
                kfree(t);
        }
 }