RxRPC: Error handling for rxrpc_alloc_connection()
[safe/jmp/linux-2.6] / net / core / neighbour.c
index d4fae81..a1cbce7 100644 (file)
@@ -472,26 +472,40 @@ out_neigh_release:
 }
 EXPORT_SYMBOL(neigh_create);
 
-struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
-               struct net *net, const void *pkey, struct net_device *dev)
+static u32 pneigh_hash(const void *pkey, int key_len)
 {
-       struct pneigh_entry *n;
-       int key_len = tbl->key_len;
        u32 hash_val = *(u32 *)(pkey + key_len - 4);
-
        hash_val ^= (hash_val >> 16);
        hash_val ^= hash_val >> 8;
        hash_val ^= hash_val >> 4;
        hash_val &= PNEIGH_HASHMASK;
+       return hash_val;
+}
 
-       for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
+static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
+                                             struct net *net,
+                                             const void *pkey,
+                                             int key_len,
+                                             struct net_device *dev)
+{
+       while (n) {
                if (!memcmp(n->key, pkey, key_len) &&
-                   (pneigh_net(n) == net) &&
+                   net_eq(pneigh_net(n), net) &&
                    (n->dev == dev || !n->dev))
-                       break;
+                       return n;
+               n = n->next;
        }
+       return NULL;
+}
 
-       return n;
+struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
+               struct net *net, const void *pkey, struct net_device *dev)
+{
+       int key_len = tbl->key_len;
+       u32 hash_val = pneigh_hash(pkey, key_len);
+
+       return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
+                                net, pkey, key_len, dev);
 }
 EXPORT_SYMBOL_GPL(__pneigh_lookup);
 
@@ -501,26 +515,14 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
 {
        struct pneigh_entry *n;
        int key_len = tbl->key_len;
-       u32 hash_val = *(u32 *)(pkey + key_len - 4);
-
-       hash_val ^= (hash_val >> 16);
-       hash_val ^= hash_val >> 8;
-       hash_val ^= hash_val >> 4;
-       hash_val &= PNEIGH_HASHMASK;
+       u32 hash_val = pneigh_hash(pkey, key_len);
 
        read_lock_bh(&tbl->lock);
-
-       for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
-               if (!memcmp(n->key, pkey, key_len) &&
-                   net_eq(pneigh_net(n), net) &&
-                   (n->dev == dev || !n->dev)) {
-                       read_unlock_bh(&tbl->lock);
-                       goto out;
-               }
-       }
+       n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
+                             net, pkey, key_len, dev);
        read_unlock_bh(&tbl->lock);
-       n = NULL;
-       if (!creat)
+
+       if (n || !creat)
                goto out;
 
        ASSERT_RTNL();
@@ -529,9 +531,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
        if (!n)
                goto out;
 
-#ifdef CONFIG_NET_NS
-       n->net = hold_net(net);
-#endif
+       write_pnet(&n->net, hold_net(net));
        memcpy(n->key, pkey, key_len);
        n->dev = dev;
        if (dev)
@@ -561,12 +561,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
 {
        struct pneigh_entry *n, **np;
        int key_len = tbl->key_len;
-       u32 hash_val = *(u32 *)(pkey + key_len - 4);
-
-       hash_val ^= (hash_val >> 16);
-       hash_val ^= hash_val >> 8;
-       hash_val ^= hash_val >> 4;
-       hash_val &= PNEIGH_HASHMASK;
+       u32 hash_val = pneigh_hash(pkey, key_len);
 
        write_lock_bh(&tbl->lock);
        for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
@@ -876,8 +871,7 @@ static void neigh_timer_handler(unsigned long arg)
                write_unlock(&neigh->lock);
                neigh->ops->solicit(neigh, skb);
                atomic_inc(&neigh->probes);
-               if (skb)
-                       kfree_skb(skb);
+               kfree_skb(skb);
        } else {
 out:
                write_unlock(&neigh->lock);
@@ -913,8 +907,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        neigh->updated = jiffies;
                        write_unlock_bh(&neigh->lock);
 
-                       if (skb)
-                               kfree_skb(skb);
+                       kfree_skb(skb);
                        return 1;
                }
        } else if (neigh->nud_state & NUD_STALE) {
@@ -930,9 +923,9 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        if (skb_queue_len(&neigh->arp_queue) >=
                            neigh->parms->queue_len) {
                                struct sk_buff *buff;
-                               buff = neigh->arp_queue.next;
-                               __skb_unlink(buff, &neigh->arp_queue);
+                               buff = __skb_dequeue(&neigh->arp_queue);
                                kfree_skb(buff);
+                               NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
                        }
                        __skb_queue_tail(&neigh->arp_queue, skb);
                }
@@ -1261,24 +1254,20 @@ static void neigh_proxy_process(unsigned long arg)
        struct neigh_table *tbl = (struct neigh_table *)arg;
        long sched_next = 0;
        unsigned long now = jiffies;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *n;
 
        spin_lock(&tbl->proxy_queue.lock);
 
-       skb = tbl->proxy_queue.next;
-
-       while (skb != (struct sk_buff *)&tbl->proxy_queue) {
-               struct sk_buff *back = skb;
-               long tdif = NEIGH_CB(back)->sched_next - now;
+       skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
+               long tdif = NEIGH_CB(skb)->sched_next - now;
 
-               skb = skb->next;
                if (tdif <= 0) {
-                       struct net_device *dev = back->dev;
-                       __skb_unlink(back, &tbl->proxy_queue);
+                       struct net_device *dev = skb->dev;
+                       __skb_unlink(skb, &tbl->proxy_queue);
                        if (tbl->proxy_redo && netif_running(dev))
-                               tbl->proxy_redo(back);
+                               tbl->proxy_redo(skb);
                        else
-                               kfree_skb(back);
+                               kfree_skb(skb);
 
                        dev_put(dev);
                } else if (!sched_next || tdif < sched_next)
@@ -1336,9 +1325,9 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
                                      struct neigh_table *tbl)
 {
        struct neigh_parms *p, *ref;
-       struct net *net;
+       struct net *net = dev_net(dev);
+       const struct net_device_ops *ops = dev->netdev_ops;
 
-       net = dev_net(dev);
        ref = lookup_neigh_params(tbl, net, 0);
        if (!ref)
                return NULL;
@@ -1347,20 +1336,17 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
        if (p) {
                p->tbl            = tbl;
                atomic_set(&p->refcnt, 1);
-               INIT_RCU_HEAD(&p->rcu_head);
                p->reachable_time =
                                neigh_rand_reach_time(p->base_reachable_time);
 
-               if (dev->neigh_setup && dev->neigh_setup(dev, p)) {
+               if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
                        kfree(p);
                        return NULL;
                }
 
                dev_hold(dev);
                p->dev = dev;
-#ifdef CONFIG_NET_NS
-               p->net = hold_net(net);
-#endif
+               write_pnet(&p->net, hold_net(net));
                p->sysctl_table = NULL;
                write_lock_bh(&tbl->lock);
                p->next         = tbl->parms.next;
@@ -1415,11 +1401,8 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
        unsigned long now = jiffies;
        unsigned long phsize;
 
-#ifdef CONFIG_NET_NS
-       tbl->parms.net = &init_net;
-#endif
+       write_pnet(&tbl->parms.net, &init_net);
        atomic_set(&tbl->parms.refcnt, 1);
-       INIT_RCU_HEAD(&tbl->parms.rcu_head);
        tbl->parms.reachable_time =
                          neigh_rand_reach_time(tbl->parms.base_reachable_time);
 
@@ -1433,11 +1416,9 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
                panic("cannot create neighbour cache statistics");
 
 #ifdef CONFIG_PROC_FS
-       tbl->pde = proc_create(tbl->id, 0, init_net.proc_net_stat,
-                              &neigh_stat_seq_fops);
-       if (!tbl->pde)
+       if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
+                             &neigh_stat_seq_fops, tbl))
                panic("cannot create neighbour proc dir entry");
-       tbl->pde->data = tbl;
 #endif
 
        tbl->hash_mask = 1;
@@ -1673,7 +1654,11 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                                flags &= ~NEIGH_UPDATE_F_OVERRIDE;
                }
 
-               err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
+               if (ndm->ndm_flags & NTF_USE) {
+                       neigh_event_send(neigh, NULL);
+                       err = 0;
+               } else
+                       err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
                neigh_release(neigh);
                goto out_dev_put;
        }
@@ -1718,7 +1703,8 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
        return nla_nest_end(skb, nest);
 
 nla_put_failure:
-       return nla_nest_cancel(skb, nest);
+       nla_nest_cancel(skb, nest);
+       return -EMSGSIZE;
 }
 
 static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
@@ -2010,8 +1996,8 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
                        if (!net_eq(neigh_parms_net(p), net))
                                continue;
 
-                       if (nidx++ < neigh_skip)
-                               continue;
+                       if (nidx < neigh_skip)
+                               goto next;
 
                        if (neightbl_fill_param_info(skb, tbl, p,
                                                     NETLINK_CB(cb->skb).pid,
@@ -2019,6 +2005,8 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
                                                     RTM_NEWNEIGHTBL,
                                                     NLM_F_MULTI) <= 0)
                                goto out;
+               next:
+                       nidx++;
                }
 
                neigh_skip = 0;
@@ -2061,9 +2049,9 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
                goto nla_put_failure;
        }
 
-       ci.ndm_used      = now - neigh->used;
-       ci.ndm_confirmed = now - neigh->confirmed;
-       ci.ndm_updated   = now - neigh->updated;
+       ci.ndm_used      = jiffies_to_clock_t(now - neigh->used);
+       ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
+       ci.ndm_updated   = jiffies_to_clock_t(now - neigh->updated);
        ci.ndm_refcnt    = atomic_read(&neigh->refcnt) - 1;
        read_unlock_bh(&neigh->lock);
 
@@ -2098,12 +2086,10 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
                if (h > s_h)
                        s_idx = 0;
                for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) {
-                       int lidx;
                        if (dev_net(n->dev) != net)
                                continue;
-                       lidx = idx++;
-                       if (lidx < s_idx)
-                               continue;
+                       if (idx < s_idx)
+                               goto next;
                        if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
                                            cb->nlh->nlmsg_seq,
                                            RTM_NEWNEIGH,
@@ -2112,6 +2098,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
                                rc = -1;
                                goto out;
                        }
+               next:
+                       idx++;
                }
        }
        read_unlock_bh(&tbl->lock);
@@ -2283,6 +2271,7 @@ static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
        struct neighbour *n = neigh_get_first(seq);
 
        if (n) {
+               --(*pos);
                while (*pos) {
                        n = neigh_get_next(seq, n, pos);
                        if (!n)
@@ -2343,6 +2332,7 @@ static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
        struct pneigh_entry *pn = pneigh_get_first(seq);
 
        if (pn) {
+               --(*pos);
                while (*pos) {
                        pn = pneigh_get_next(seq, pn, pos);
                        if (!pn)
@@ -2356,10 +2346,11 @@ static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
 {
        struct neigh_seq_state *state = seq->private;
        void *rc;
+       loff_t idxpos = *pos;
 
-       rc = neigh_get_idx(seq, pos);
+       rc = neigh_get_idx(seq, &idxpos);
        if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
-               rc = pneigh_get_idx(seq, pos);
+               rc = pneigh_get_idx(seq, &idxpos);
 
        return rc;
 }
@@ -2368,7 +2359,6 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
        __acquires(tbl->lock)
 {
        struct neigh_seq_state *state = seq->private;
-       loff_t pos_minus_one;
 
        state->tbl = tbl;
        state->bucket = 0;
@@ -2376,8 +2366,7 @@ void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl
 
        read_lock_bh(&tbl->lock);
 
-       pos_minus_one = *pos - 1;
-       return *pos ? neigh_get_idx_any(seq, &pos_minus_one) : SEQ_START_TOKEN;
+       return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
 }
 EXPORT_SYMBOL(neigh_seq_start);
 
@@ -2387,7 +2376,7 @@ void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        void *rc;
 
        if (v == SEQ_START_TOKEN) {
-               rc = neigh_get_idx(seq, pos);
+               rc = neigh_get_first(seq);
                goto out;
        }
 
@@ -2429,7 +2418,7 @@ static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
@@ -2444,7 +2433,7 @@ static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct neigh_table *tbl = pde->data;
        int cpu;
 
-       for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
@@ -2465,12 +2454,12 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
        struct neigh_statistics *st = v;
 
        if (v == SEQ_START_TOKEN) {
-               seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs\n");
+               seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs unresolved_discards\n");
                return 0;
        }
 
        seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
-                       "%08lx %08lx  %08lx %08lx\n",
+                       "%08lx %08lx  %08lx %08lx %08lx\n",
                   atomic_read(&tbl->entries),
 
                   st->allocs,
@@ -2486,7 +2475,8 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
                   st->rcv_probes_ucast,
 
                   st->periodic_gc_runs,
-                  st->forced_gc_runs
+                  st->forced_gc_runs,
+                  st->unres_discards
                   );
 
        return 0;
@@ -2546,7 +2536,8 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
@@ -2573,128 +2564,128 @@ static struct neigh_sysctl_table {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .ctl_name       = NET_NEIGH_UCAST_SOLICIT,
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .ctl_name       = NET_NEIGH_APP_SOLICIT,
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .procname       = "retrans_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_userhz_jiffies,
+                       .proc_handler   = proc_dointvec_userhz_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_REACHABLE_TIME,
                        .procname       = "base_reachable_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_jiffies,
-                       .strategy       = &sysctl_jiffies,
+                       .proc_handler   = proc_dointvec_jiffies,
+                       .strategy       = sysctl_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_DELAY_PROBE_TIME,
                        .procname       = "delay_first_probe_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_jiffies,
-                       .strategy       = &sysctl_jiffies,
+                       .proc_handler   = proc_dointvec_jiffies,
+                       .strategy       = sysctl_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_GC_STALE_TIME,
                        .procname       = "gc_stale_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_jiffies,
-                       .strategy       = &sysctl_jiffies,
+                       .proc_handler   = proc_dointvec_jiffies,
+                       .strategy       = sysctl_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_UNRES_QLEN,
                        .procname       = "unres_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .ctl_name       = NET_NEIGH_PROXY_QLEN,
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .procname       = "anycast_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_userhz_jiffies,
+                       .proc_handler   = proc_dointvec_userhz_jiffies,
                },
                {
                        .procname       = "proxy_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_userhz_jiffies,
+                       .proc_handler   = proc_dointvec_userhz_jiffies,
                },
                {
                        .procname       = "locktime",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_userhz_jiffies,
+                       .proc_handler   = proc_dointvec_userhz_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_RETRANS_TIME_MS,
                        .procname       = "retrans_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_ms_jiffies,
-                       .strategy       = &sysctl_ms_jiffies,
+                       .proc_handler   = proc_dointvec_ms_jiffies,
+                       .strategy       = sysctl_ms_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_REACHABLE_TIME_MS,
                        .procname       = "base_reachable_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_ms_jiffies,
-                       .strategy       = &sysctl_ms_jiffies,
+                       .proc_handler   = proc_dointvec_ms_jiffies,
+                       .strategy       = sysctl_ms_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_GC_INTERVAL,
                        .procname       = "gc_interval",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec_jiffies,
-                       .strategy       = &sysctl_jiffies,
+                       .proc_handler   = proc_dointvec_jiffies,
+                       .strategy       = sysctl_jiffies,
                },
                {
                        .ctl_name       = NET_NEIGH_GC_THRESH1,
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .ctl_name       = NET_NEIGH_GC_THRESH2,
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .ctl_name       = NET_NEIGH_GC_THRESH3,
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = &proc_dointvec,
+                       .proc_handler   = proc_dointvec,
                },
                {},
        },