net: Move all of the network sysctls without a namespace into init_net.
[linux-2.6-block.git] / net / core / neighbour.c
index 2a83914b027743fbf047aae18315ab0197bc6e0c..0c2df3d3cfbf4e40c468c796f11d1e8ca3d76619 100644 (file)
@@ -890,7 +890,7 @@ static void neigh_timer_handler(unsigned long arg)
 {
        unsigned long now, next;
        struct neighbour *neigh = (struct neighbour *)arg;
-       unsigned state;
+       unsigned int state;
        int notify = 0;
 
        write_lock(&neigh->lock);
@@ -1500,7 +1500,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms)
 
 static struct lock_class_key neigh_table_proxy_queue_class;
 
-void neigh_table_init_no_netlink(struct neigh_table *tbl)
+static void neigh_table_init_no_netlink(struct neigh_table *tbl)
 {
        unsigned long now = jiffies;
        unsigned long phsize;
@@ -1538,7 +1538,6 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
        tbl->last_flush = now;
        tbl->last_rand  = now + tbl->parms.reachable_time * 20;
 }
-EXPORT_SYMBOL(neigh_table_init_no_netlink);
 
 void neigh_table_init(struct neigh_table *tbl)
 {
@@ -1768,29 +1767,29 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
        if (nest == NULL)
                return -ENOBUFS;
 
-       if (parms->dev)
-               NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
-
-       NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
-       NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
-       /* approximative value for deprecated QUEUE_LEN (in packets) */
-       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
-                   DIV_ROUND_UP(parms->queue_len_bytes,
-                                SKB_TRUESIZE(ETH_FRAME_LEN)));
-       NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
-       NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
-       NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
-       NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
-       NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
-       NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
-                     parms->base_reachable_time);
-       NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
-       NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
-       NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
-       NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
-       NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
-       NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
-
+       if ((parms->dev &&
+            nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
+           nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
+           nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) ||
+           /* approximative value for deprecated QUEUE_LEN (in packets) */
+           nla_put_u32(skb, NDTPA_QUEUE_LEN,
+                       DIV_ROUND_UP(parms->queue_len_bytes,
+                                    SKB_TRUESIZE(ETH_FRAME_LEN))) ||
+           nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) ||
+           nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) ||
+           nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) ||
+           nla_put_u32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes) ||
+           nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
+           nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
+                         parms->base_reachable_time) ||
+           nla_put_msecs(skb, NDTPA_GC_STALETIME, parms->gc_staletime) ||
+           nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
+                         parms->delay_probe_time) ||
+           nla_put_msecs(skb, NDTPA_RETRANS_TIME, parms->retrans_time) ||
+           nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay) ||
+           nla_put_msecs(skb, NDTPA_PROXY_DELAY, parms->proxy_delay) ||
+           nla_put_msecs(skb, NDTPA_LOCKTIME, parms->locktime))
+               goto nla_put_failure;
        return nla_nest_end(skb, nest);
 
 nla_put_failure:
@@ -1815,12 +1814,12 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
        ndtmsg->ndtm_pad1   = 0;
        ndtmsg->ndtm_pad2   = 0;
 
-       NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
-       NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
-       NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
-       NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
-       NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
-
+       if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
+           nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
+           nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
+           nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
+           nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
+               goto nla_put_failure;
        {
                unsigned long now = jiffies;
                unsigned int flush_delta = now - tbl->last_flush;
@@ -1841,7 +1840,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
                ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
                rcu_read_unlock_bh();
 
-               NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
+               if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
+                       goto nla_put_failure;
        }
 
        {
@@ -1866,7 +1866,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
                        ndst.ndts_forced_gc_runs        += st->forced_gc_runs;
                }
 
-               NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
+               if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
+                       goto nla_put_failure;
        }
 
        BUG_ON(tbl->parms.dev);
@@ -2137,7 +2138,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
        ndm->ndm_type    = neigh->type;
        ndm->ndm_ifindex = neigh->dev->ifindex;
 
-       NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
+       if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
+               goto nla_put_failure;
 
        read_lock_bh(&neigh->lock);
        ndm->ndm_state   = neigh->nud_state;
@@ -2157,8 +2159,39 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
        ci.ndm_refcnt    = atomic_read(&neigh->refcnt) - 1;
        read_unlock_bh(&neigh->lock);
 
-       NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
-       NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
+       if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
+           nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
+               goto nla_put_failure;
+
+       return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+       nlmsg_cancel(skb, nlh);
+       return -EMSGSIZE;
+}
+
+static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
+                           u32 pid, u32 seq, int type, unsigned int flags,
+                           struct neigh_table *tbl)
+{
+       struct nlmsghdr *nlh;
+       struct ndmsg *ndm;
+
+       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
+       if (nlh == NULL)
+               return -EMSGSIZE;
+
+       ndm = nlmsg_data(nlh);
+       ndm->ndm_family  = tbl->family;
+       ndm->ndm_pad1    = 0;
+       ndm->ndm_pad2    = 0;
+       ndm->ndm_flags   = pn->flags | NTF_PROXY;
+       ndm->ndm_type    = NDA_DST;
+       ndm->ndm_ifindex = pn->dev->ifindex;
+       ndm->ndm_state   = NUD_NONE;
+
+       if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
+               goto nla_put_failure;
 
        return nlmsg_end(skb, nlh);
 
@@ -2216,23 +2249,78 @@ out:
        return rc;
 }
 
+static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
+                            struct netlink_callback *cb)
+{
+       struct pneigh_entry *n;
+       struct net *net = sock_net(skb->sk);
+       int rc, h, s_h = cb->args[3];
+       int idx, s_idx = idx = cb->args[4];
+
+       read_lock_bh(&tbl->lock);
+
+       for (h = 0; h <= PNEIGH_HASHMASK; h++) {
+               if (h < s_h)
+                       continue;
+               if (h > s_h)
+                       s_idx = 0;
+               for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
+                       if (dev_net(n->dev) != net)
+                               continue;
+                       if (idx < s_idx)
+                               goto next;
+                       if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
+                                           cb->nlh->nlmsg_seq,
+                                           RTM_NEWNEIGH,
+                                           NLM_F_MULTI, tbl) <= 0) {
+                               read_unlock_bh(&tbl->lock);
+                               rc = -1;
+                               goto out;
+                       }
+               next:
+                       idx++;
+               }
+       }
+
+       read_unlock_bh(&tbl->lock);
+       rc = skb->len;
+out:
+       cb->args[3] = h;
+       cb->args[4] = idx;
+       return rc;
+
+}
+
 static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct neigh_table *tbl;
        int t, family, s_t;
+       int proxy = 0;
+       int err = 0;
 
        read_lock(&neigh_tbl_lock);
        family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
+
+       /* check for full ndmsg structure presence, family member is
+        * the same for both structures
+        */
+       if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
+           ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
+               proxy = 1;
+
        s_t = cb->args[0];
 
-       for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
+       for (tbl = neigh_tables, t = 0; tbl && (err >= 0);
+            tbl = tbl->next, t++) {
                if (t < s_t || (family && tbl->family != family))
                        continue;
                if (t > s_t)
                        memset(&cb->args[1], 0, sizeof(cb->args) -
                                                sizeof(cb->args[0]));
-               if (neigh_dump_table(tbl, skb, cb) < 0)
-                       break;
+               if (proxy)
+                       err = pneigh_dump_table(tbl, skb, cb);
+               else
+                       err = neigh_dump_table(tbl, skb, cb);
        }
        read_unlock(&neigh_tbl_lock);
 
@@ -2929,7 +3017,7 @@ void neigh_sysctl_unregister(struct neigh_parms *p)
        if (p->sysctl_table) {
                struct neigh_sysctl_table *t = p->sysctl_table;
                p->sysctl_table = NULL;
-               unregister_sysctl_table(t->sysctl_header);
+               unregister_net_sysctl_table(t->sysctl_header);
                kfree(t->dev_name);
                kfree(t);
        }