mac80211: let unused MPP table entries timeout
[cascardo/linux.git] / net / mac80211 / mesh_pathtbl.c
index 40ed206..29e5040 100644 (file)
@@ -940,6 +940,46 @@ enddel:
        return err;
 }
 
+/**
+ * mpp_path_del - delete a mesh proxy path from the table
+ *
+ * @addr: addr address (ETH_ALEN length)
+ * @sdata: local subif
+ *
+ * Returns: 0 if successful
+ */
+static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
+{
+       struct mesh_table *tbl;
+       struct mesh_path *mpath;
+       struct mpath_node *node;
+       struct hlist_head *bucket;
+       int hash_idx;
+       int err = 0;
+
+       read_lock_bh(&pathtbl_resize_lock);
+       tbl = resize_dereference_mpp_paths();
+       hash_idx = mesh_table_hash(addr, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
+
+       spin_lock(&tbl->hashwlock[hash_idx]);
+       hlist_for_each_entry(node, bucket, list) {
+               mpath = node->mpath;
+               if (mpath->sdata == sdata &&
+                   ether_addr_equal(addr, mpath->dst)) {
+                       __mesh_path_del(tbl, node);
+                       goto enddel;
+               }
+       }
+
+       err = -ENXIO;
+enddel:
+       mesh_paths_generation++;
+       spin_unlock(&tbl->hashwlock[hash_idx]);
+       read_unlock_bh(&pathtbl_resize_lock);
+       return err;
+}
+
 /**
  * mesh_path_tx_pending - sends pending frames in a mesh path queue
  *
@@ -1154,6 +1194,17 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
                     time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
                        mesh_path_del(mpath->sdata, mpath->dst);
        }
+
+       tbl = rcu_dereference(mpp_paths);
+       for_each_mesh_entry(tbl, node, i) {
+               if (node->mpath->sdata != sdata)
+                       continue;
+               mpath = node->mpath;
+               if ((!(mpath->flags & MESH_PATH_FIXED)) &&
+                   time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
+                       mpp_path_del(mpath->sdata, mpath->dst);
+       }
+
        rcu_read_unlock();
 }