|
@@ -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();
|
|
|
}
|
|
|
|