Merge branch 'next' of git://git.infradead.org/users/pcmoore/selinux into next
[firefly-linux-kernel-4.4.55.git] / net / core / neighbour.c
index 70fe9e10ac867f495086810dc6ea619f69d59368..84195dacb8b63f418cac67d4039842dd72eaecc4 100644 (file)
@@ -397,25 +397,15 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
                               struct net_device *dev)
 {
        struct neighbour *n;
-       int key_len = tbl->key_len;
-       u32 hash_val;
-       struct neigh_hash_table *nht;
 
        NEIGH_CACHE_STAT_INC(tbl, lookups);
 
        rcu_read_lock_bh();
-       nht = rcu_dereference_bh(tbl->nht);
-       hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
-
-       for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
-            n != NULL;
-            n = rcu_dereference_bh(n->next)) {
-               if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
-                       if (!atomic_inc_not_zero(&n->refcnt))
-                               n = NULL;
-                       NEIGH_CACHE_STAT_INC(tbl, hits);
-                       break;
-               }
+       n = __neigh_lookup_noref(tbl, pkey, dev);
+       if (n) {
+               if (!atomic_inc_not_zero(&n->refcnt))
+                       n = NULL;
+               NEIGH_CACHE_STAT_INC(tbl, hits);
        }
 
        rcu_read_unlock_bh();
@@ -601,7 +591,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
        if (!n)
                goto out;
 
-       write_pnet(&n->net, hold_net(net));
+       write_pnet(&n->net, net);
        memcpy(n->key, pkey, key_len);
        n->dev = dev;
        if (dev)
@@ -610,7 +600,6 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
        if (tbl->pconstructor && tbl->pconstructor(n)) {
                if (dev)
                        dev_put(dev);
-               release_net(net);
                kfree(n);
                n = NULL;
                goto out;
@@ -644,7 +633,6 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
                                tbl->pdestructor(n);
                        if (n->dev)
                                dev_put(n->dev);
-                       release_net(pneigh_net(n));
                        kfree(n);
                        return 0;
                }
@@ -667,7 +655,6 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
                                        tbl->pdestructor(n);
                                if (n->dev)
                                        dev_put(n->dev);
-                               release_net(pneigh_net(n));
                                kfree(n);
                                continue;
                        }
@@ -830,10 +817,9 @@ out:
 static __inline__ int neigh_max_probes(struct neighbour *n)
 {
        struct neigh_parms *p = n->parms;
-       int max_probes = NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES);
-       if (!(n->nud_state & NUD_PROBE))
-               max_probes += NEIGH_VAR(p, MCAST_PROBES);
-       return max_probes;
+       return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
+              (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
+               NEIGH_VAR(p, MCAST_PROBES));
 }
 
 static void neigh_invalidate(struct neighbour *neigh)
@@ -927,6 +913,7 @@ static void neigh_timer_handler(unsigned long arg)
                        neigh->nud_state = NUD_PROBE;
                        neigh->updated = jiffies;
                        atomic_set(&neigh->probes, 0);
+                       notify = 1;
                        next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
                }
        } else {
@@ -971,6 +958,8 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
        rc = 0;
        if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
                goto out_unlock_bh;
+       if (neigh->dead)
+               goto out_dead;
 
        if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
                if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
@@ -1027,6 +1016,13 @@ out_unlock_bh:
                write_unlock(&neigh->lock);
        local_bh_enable();
        return rc;
+
+out_dead:
+       if (neigh->nud_state & NUD_STALE)
+               goto out_unlock_bh;
+       write_unlock_bh(&neigh->lock);
+       kfree_skb(skb);
+       return 1;
 }
 EXPORT_SYMBOL(__neigh_event_send);
 
@@ -1090,6 +1086,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
        if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
            (old & (NUD_NOARP | NUD_PERMANENT)))
                goto out;
+       if (neigh->dead)
+               goto out;
 
        if (!(new & NUD_VALID)) {
                neigh_del_timer(neigh);
@@ -1158,6 +1156,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
 
        if (new != old) {
                neigh_del_timer(neigh);
+               if (new & NUD_PROBE)
+                       atomic_set(&neigh->probes, 0);
                if (new & NUD_IN_TIMER)
                        neigh_add_timer(neigh, (jiffies +
                                                ((new & NUD_REACHABLE) ?
@@ -1239,6 +1239,8 @@ EXPORT_SYMBOL(neigh_update);
  */
 void __neigh_set_probe_once(struct neighbour *neigh)
 {
+       if (neigh->dead)
+               return;
        neigh->updated = jiffies;
        if (!(neigh->nud_state & NUD_FAILED))
                return;
@@ -1263,10 +1265,10 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
 EXPORT_SYMBOL(neigh_event_ns);
 
 /* called with read_lock_bh(&n->lock); */
-static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
+static void neigh_hh_init(struct neighbour *n)
 {
-       struct net_device *dev = dst->dev;
-       __be16 prot = dst->ops->protocol;
+       struct net_device *dev = n->dev;
+       __be16 prot = n->tbl->protocol;
        struct hh_cache *hh = &n->hh;
 
        write_lock_bh(&n->lock);
@@ -1280,43 +1282,19 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
        write_unlock_bh(&n->lock);
 }
 
-/* This function can be used in contexts, where only old dev_queue_xmit
- * worked, f.e. if you want to override normal output path (eql, shaper),
- * but resolution is not made yet.
- */
-
-int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
-{
-       struct net_device *dev = skb->dev;
-
-       __skb_pull(skb, skb_network_offset(skb));
-
-       if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
-                           skb->len) < 0 &&
-           dev_rebuild_header(skb))
-               return 0;
-
-       return dev_queue_xmit(skb);
-}
-EXPORT_SYMBOL(neigh_compat_output);
-
 /* Slow and careful. */
 
 int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb_dst(skb);
        int rc = 0;
 
-       if (!dst)
-               goto discard;
-
        if (!neigh_event_send(neigh, skb)) {
                int err;
                struct net_device *dev = neigh->dev;
                unsigned int seq;
 
                if (dev->header_ops->cache && !neigh->hh.hh_len)
-                       neigh_hh_init(neigh, dst);
+                       neigh_hh_init(neigh);
 
                do {
                        __skb_pull(skb, skb_network_offset(skb));
@@ -1332,8 +1310,6 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
        }
 out:
        return rc;
-discard:
-       neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
 out_kfree_skb:
        rc = -EINVAL;
        kfree_skb(skb);
@@ -1464,11 +1440,10 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
                dev_hold(dev);
                p->dev = dev;
-               write_pnet(&p->net, hold_net(net));
+               write_pnet(&p->net, net);
                p->sysctl_table = NULL;
 
                if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
-                       release_net(net);
                        dev_put(dev);
                        kfree(p);
                        return NULL;
@@ -1508,7 +1483,6 @@ EXPORT_SYMBOL(neigh_parms_release);
 
 static void neigh_parms_destroy(struct neigh_parms *parms)
 {
-       release_net(neigh_parms_net(parms));
        kfree(parms);
 }
 
@@ -1783,6 +1757,8 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
                        NEIGH_VAR(parms, UCAST_PROBES)) ||
            nla_put_u32(skb, NDTPA_MCAST_PROBES,
                        NEIGH_VAR(parms, MCAST_PROBES)) ||
+           nla_put_u32(skb, NDTPA_MCAST_REPROBES,
+                       NEIGH_VAR(parms, MCAST_REPROBES)) ||
            nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
            nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
                          NEIGH_VAR(parms, BASE_REACHABLE_TIME)) ||
@@ -1942,6 +1918,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
        [NDTPA_APP_PROBES]              = { .type = NLA_U32 },
        [NDTPA_UCAST_PROBES]            = { .type = NLA_U32 },
        [NDTPA_MCAST_PROBES]            = { .type = NLA_U32 },
+       [NDTPA_MCAST_REPROBES]          = { .type = NLA_U32 },
        [NDTPA_BASE_REACHABLE_TIME]     = { .type = NLA_U64 },
        [NDTPA_GC_STALETIME]            = { .type = NLA_U64 },
        [NDTPA_DELAY_PROBE_TIME]        = { .type = NLA_U64 },
@@ -2042,6 +2019,10 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
                                NEIGH_VAR_SET(p, MCAST_PROBES,
                                              nla_get_u32(tbp[i]));
                                break;
+                       case NDTPA_MCAST_REPROBES:
+                               NEIGH_VAR_SET(p, MCAST_REPROBES,
+                                             nla_get_u32(tbp[i]));
+                               break;
                        case NDTPA_BASE_REACHABLE_TIME:
                                NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
                                              nla_get_msecs(tbp[i]));
@@ -2427,6 +2408,40 @@ void __neigh_for_each_release(struct neigh_table *tbl,
 }
 EXPORT_SYMBOL(__neigh_for_each_release);
 
+int neigh_xmit(int index, struct net_device *dev,
+              const void *addr, struct sk_buff *skb)
+{
+       int err = -EAFNOSUPPORT;
+       if (likely(index < NEIGH_NR_TABLES)) {
+               struct neigh_table *tbl;
+               struct neighbour *neigh;
+
+               tbl = neigh_tables[index];
+               if (!tbl)
+                       goto out;
+               neigh = __neigh_lookup_noref(tbl, addr, dev);
+               if (!neigh)
+                       neigh = __neigh_create(tbl, addr, dev, false);
+               err = PTR_ERR(neigh);
+               if (IS_ERR(neigh))
+                       goto out_kfree_skb;
+               err = neigh->output(neigh, skb);
+       }
+       else if (index == NEIGH_LINK_TABLE) {
+               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+                                     addr, NULL, skb->len);
+               if (err < 0)
+                       goto out_kfree_skb;
+               err = dev_queue_xmit(skb);
+       }
+out:
+       return err;
+out_kfree_skb:
+       kfree_skb(skb);
+       goto out;
+}
+EXPORT_SYMBOL(neigh_xmit);
+
 #ifdef CONFIG_PROC_FS
 
 static struct neighbour *neigh_get_first(struct seq_file *seq)
@@ -2994,6 +3009,7 @@ static struct neigh_sysctl_table {
                NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
                NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
                NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
+               NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
                NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
                NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
                NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),