batman-adv: Check hard_iface refcnt before calling function
[deliverable/linux.git] / net / batman-adv / originator.c
index e4cbb0753e37ff6681a20e8912df1f4ad1e74a05..2ed2cc89a669fc5afbeace39a807d7571618f077 100644 (file)
@@ -250,7 +250,6 @@ static void batadv_neigh_node_release(struct kref *ref)
 {
        struct hlist_node *node_tmp;
        struct batadv_neigh_node *neigh_node;
-       struct batadv_hardif_neigh_node *hardif_neigh;
        struct batadv_neigh_ifinfo *neigh_ifinfo;
        struct batadv_algo_ops *bao;
 
@@ -262,13 +261,7 @@ static void batadv_neigh_node_release(struct kref *ref)
                batadv_neigh_ifinfo_put(neigh_ifinfo);
        }
 
-       hardif_neigh = batadv_hardif_neigh_get(neigh_node->if_incoming,
-                                              neigh_node->addr);
-       if (hardif_neigh) {
-               /* batadv_hardif_neigh_get() increases refcount too */
-               batadv_hardif_neigh_put(hardif_neigh);
-               batadv_hardif_neigh_put(hardif_neigh);
-       }
+       batadv_hardif_neigh_put(neigh_node->hardif_neigh);
 
        if (bao->bat_neigh_free)
                bao->bat_neigh_free(neigh_node);
@@ -289,7 +282,7 @@ void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node)
 }
 
 /**
- * batadv_orig_node_get_router - router to the originator depending on iface
+ * batadv_orig_router_get - router to the originator depending on iface
  * @orig_node: the orig node for the router
  * @if_outgoing: the interface where the payload packet has been received or
  *  the OGM should be sent to
@@ -663,6 +656,11 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
        ether_addr_copy(neigh_node->addr, neigh_addr);
        neigh_node->if_incoming = hard_iface;
        neigh_node->orig_node = orig_node;
+       neigh_node->last_seen = jiffies;
+
+       /* increment unique neighbor refcount */
+       kref_get(&hardif_neigh->refcount);
+       neigh_node->hardif_neigh = hardif_neigh;
 
        /* extra reference for return */
        kref_init(&neigh_node->refcount);
@@ -672,9 +670,6 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
        hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
        spin_unlock_bh(&orig_node->neigh_list_lock);
 
-       /* increment unique neighbor refcount */
-       kref_get(&hardif_neigh->refcount);
-
        batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
                   "Creating new neighbor %pM for orig_node %pM on interface %s\n",
                   neigh_addr, orig_node->orig, hard_iface->net_dev->name);
@@ -1165,6 +1160,9 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                if (hard_iface->soft_iface != bat_priv->soft_iface)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                best_neigh_node = batadv_find_best_neighbor(bat_priv,
                                                            orig_node,
                                                            hard_iface);
@@ -1172,6 +1170,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                                    best_neigh_node);
                if (best_neigh_node)
                        batadv_neigh_node_put(best_neigh_node);
+
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 
@@ -1222,7 +1222,7 @@ static void batadv_purge_orig(struct work_struct *work)
        struct delayed_work *delayed_work;
        struct batadv_priv *bat_priv;
 
-       delayed_work = container_of(work, struct delayed_work, work);
+       delayed_work = to_delayed_work(work);
        bat_priv = container_of(delayed_work, struct batadv_priv, orig_work);
        _batadv_purge_orig(bat_priv);
        queue_delayed_work(batadv_event_workqueue,
This page took 0.024662 seconds and 5 git commands to generate.