aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_pathtbl.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2011-09-19 15:00:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-19 15:00:16 -0400
commitb53d63ecce17c4ddf8636def9f6e8b865c3927f9 (patch)
tree683ef774fcfb423fa35f61e4326d0ce3f6a7c283 /net/mac80211/mesh_pathtbl.c
parent765cf9976e937f1cfe9159bf4534967c8bf8eb6d (diff)
parent12e62d6f7ec475e546b40bece2045da15d6c21ef (diff)
Merge branch 'master' of ssh://infradead/~/public_git/wireless-next into for-davem
Diffstat (limited to 'net/mac80211/mesh_pathtbl.c')
-rw-r--r--net/mac80211/mesh_pathtbl.c192
1 files changed, 114 insertions, 78 deletions
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index f97d17cb073c..7f54c5042235 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -14,6 +14,7 @@
14#include <linux/spinlock.h> 14#include <linux/spinlock.h>
15#include <linux/string.h> 15#include <linux/string.h>
16#include <net/mac80211.h> 16#include <net/mac80211.h>
17#include "wme.h"
17#include "ieee80211_i.h" 18#include "ieee80211_i.h"
18#include "mesh.h" 19#include "mesh.h"
19 20
@@ -48,8 +49,10 @@ static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
48int mesh_paths_generation; 49int mesh_paths_generation;
49 50
50/* This lock will have the grow table function as writer and add / delete nodes 51/* This lock will have the grow table function as writer and add / delete nodes
51 * as readers. When reading the table (i.e. doing lookups) we are well protected 52 * as readers. RCU provides sufficient protection only when reading the table
52 * by RCU 53 * (i.e. doing lookups). Adding or adding or removing nodes requires we take
54 * the read lock or we risk operating on an old table. The write lock is only
55 * needed when modifying the number of buckets a table.
53 */ 56 */
54static DEFINE_RWLOCK(pathtbl_resize_lock); 57static DEFINE_RWLOCK(pathtbl_resize_lock);
55 58
@@ -210,6 +213,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
210 struct ieee80211_hdr *hdr; 213 struct ieee80211_hdr *hdr;
211 struct sk_buff_head tmpq; 214 struct sk_buff_head tmpq;
212 unsigned long flags; 215 unsigned long flags;
216 struct ieee80211_sub_if_data *sdata = mpath->sdata;
213 217
214 rcu_assign_pointer(mpath->next_hop, sta); 218 rcu_assign_pointer(mpath->next_hop, sta);
215 219
@@ -220,6 +224,8 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
220 while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { 224 while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
221 hdr = (struct ieee80211_hdr *) skb->data; 225 hdr = (struct ieee80211_hdr *) skb->data;
222 memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); 226 memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
227 skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
228 ieee80211_set_qos_hdr(sdata, skb);
223 __skb_queue_tail(&tmpq, skb); 229 __skb_queue_tail(&tmpq, skb);
224 } 230 }
225 231
@@ -333,25 +339,14 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
333} 339}
334 340
335 341
336/** 342static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst,
337 * mesh_path_lookup - look up a path in the mesh path table 343 struct ieee80211_sub_if_data *sdata)
338 * @dst: hardware address (ETH_ALEN length) of destination
339 * @sdata: local subif
340 *
341 * Returns: pointer to the mesh path structure, or NULL if not found
342 *
343 * Locking: must be called within a read rcu section.
344 */
345struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
346{ 344{
347 struct mesh_path *mpath; 345 struct mesh_path *mpath;
348 struct hlist_node *n; 346 struct hlist_node *n;
349 struct hlist_head *bucket; 347 struct hlist_head *bucket;
350 struct mesh_table *tbl;
351 struct mpath_node *node; 348 struct mpath_node *node;
352 349
353 tbl = rcu_dereference(mesh_paths);
354
355 bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; 350 bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
356 hlist_for_each_entry_rcu(node, n, bucket, list) { 351 hlist_for_each_entry_rcu(node, n, bucket, list) {
357 mpath = node->mpath; 352 mpath = node->mpath;
@@ -359,8 +354,7 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
359 memcmp(dst, mpath->dst, ETH_ALEN) == 0) { 354 memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
360 if (MPATH_EXPIRED(mpath)) { 355 if (MPATH_EXPIRED(mpath)) {
361 spin_lock_bh(&mpath->state_lock); 356 spin_lock_bh(&mpath->state_lock);
362 if (MPATH_EXPIRED(mpath)) 357 mpath->flags &= ~MESH_PATH_ACTIVE;
363 mpath->flags &= ~MESH_PATH_ACTIVE;
364 spin_unlock_bh(&mpath->state_lock); 358 spin_unlock_bh(&mpath->state_lock);
365 } 359 }
366 return mpath; 360 return mpath;
@@ -369,31 +363,23 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
369 return NULL; 363 return NULL;
370} 364}
371 365
372struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) 366/**
367 * mesh_path_lookup - look up a path in the mesh path table
368 * @dst: hardware address (ETH_ALEN length) of destination
369 * @sdata: local subif
370 *
371 * Returns: pointer to the mesh path structure, or NULL if not found
372 *
373 * Locking: must be called within a read rcu section.
374 */
375struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
373{ 376{
374 struct mesh_path *mpath; 377 return path_lookup(rcu_dereference(mesh_paths), dst, sdata);
375 struct hlist_node *n; 378}
376 struct hlist_head *bucket;
377 struct mesh_table *tbl;
378 struct mpath_node *node;
379
380 tbl = rcu_dereference(mpp_paths);
381 379
382 bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; 380struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
383 hlist_for_each_entry_rcu(node, n, bucket, list) { 381{
384 mpath = node->mpath; 382 return path_lookup(rcu_dereference(mpp_paths), dst, sdata);
385 if (mpath->sdata == sdata &&
386 memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
387 if (MPATH_EXPIRED(mpath)) {
388 spin_lock_bh(&mpath->state_lock);
389 if (MPATH_EXPIRED(mpath))
390 mpath->flags &= ~MESH_PATH_ACTIVE;
391 spin_unlock_bh(&mpath->state_lock);
392 }
393 return mpath;
394 }
395 }
396 return NULL;
397} 383}
398 384
399 385
@@ -420,8 +406,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
420 if (j++ == idx) { 406 if (j++ == idx) {
421 if (MPATH_EXPIRED(node->mpath)) { 407 if (MPATH_EXPIRED(node->mpath)) {
422 spin_lock_bh(&node->mpath->state_lock); 408 spin_lock_bh(&node->mpath->state_lock);
423 if (MPATH_EXPIRED(node->mpath)) 409 node->mpath->flags &= ~MESH_PATH_ACTIVE;
424 node->mpath->flags &= ~MESH_PATH_ACTIVE;
425 spin_unlock_bh(&node->mpath->state_lock); 410 spin_unlock_bh(&node->mpath->state_lock);
426 } 411 }
427 return node->mpath; 412 return node->mpath;
@@ -776,22 +761,47 @@ void mesh_plink_broken(struct sta_info *sta)
776 tbl = rcu_dereference(mesh_paths); 761 tbl = rcu_dereference(mesh_paths);
777 for_each_mesh_entry(tbl, p, node, i) { 762 for_each_mesh_entry(tbl, p, node, i) {
778 mpath = node->mpath; 763 mpath = node->mpath;
779 spin_lock_bh(&mpath->state_lock);
780 if (rcu_dereference(mpath->next_hop) == sta && 764 if (rcu_dereference(mpath->next_hop) == sta &&
781 mpath->flags & MESH_PATH_ACTIVE && 765 mpath->flags & MESH_PATH_ACTIVE &&
782 !(mpath->flags & MESH_PATH_FIXED)) { 766 !(mpath->flags & MESH_PATH_FIXED)) {
767 spin_lock_bh(&mpath->state_lock);
783 mpath->flags &= ~MESH_PATH_ACTIVE; 768 mpath->flags &= ~MESH_PATH_ACTIVE;
784 ++mpath->sn; 769 ++mpath->sn;
785 spin_unlock_bh(&mpath->state_lock); 770 spin_unlock_bh(&mpath->state_lock);
786 mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, 771 mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
787 mpath->dst, cpu_to_le32(mpath->sn), 772 mpath->dst, cpu_to_le32(mpath->sn),
788 reason, bcast, sdata); 773 reason, bcast, sdata);
789 } else 774 }
790 spin_unlock_bh(&mpath->state_lock);
791 } 775 }
792 rcu_read_unlock(); 776 rcu_read_unlock();
793} 777}
794 778
779static void mesh_path_node_reclaim(struct rcu_head *rp)
780{
781 struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
782 struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
783
784 del_timer_sync(&node->mpath->timer);
785 atomic_dec(&sdata->u.mesh.mpaths);
786 kfree(node->mpath);
787 kfree(node);
788}
789
790/* needs to be called with the corresponding hashwlock taken */
791static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
792{
793 struct mesh_path *mpath;
794 mpath = node->mpath;
795 spin_lock(&mpath->state_lock);
796 mpath->flags |= MESH_PATH_RESOLVING;
797 if (mpath->is_gate)
798 mesh_gate_del(tbl, mpath);
799 hlist_del_rcu(&node->list);
800 call_rcu(&node->rcu, mesh_path_node_reclaim);
801 spin_unlock(&mpath->state_lock);
802 atomic_dec(&tbl->entries);
803}
804
795/** 805/**
796 * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches 806 * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
797 * 807 *
@@ -812,42 +822,59 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
812 int i; 822 int i;
813 823
814 rcu_read_lock(); 824 rcu_read_lock();
815 tbl = rcu_dereference(mesh_paths); 825 read_lock_bh(&pathtbl_resize_lock);
826 tbl = resize_dereference_mesh_paths();
816 for_each_mesh_entry(tbl, p, node, i) { 827 for_each_mesh_entry(tbl, p, node, i) {
817 mpath = node->mpath; 828 mpath = node->mpath;
818 if (rcu_dereference(mpath->next_hop) == sta) 829 if (rcu_dereference(mpath->next_hop) == sta) {
819 mesh_path_del(mpath->dst, mpath->sdata); 830 spin_lock_bh(&tbl->hashwlock[i]);
831 __mesh_path_del(tbl, node);
832 spin_unlock_bh(&tbl->hashwlock[i]);
833 }
820 } 834 }
835 read_unlock_bh(&pathtbl_resize_lock);
821 rcu_read_unlock(); 836 rcu_read_unlock();
822} 837}
823 838
824void mesh_path_flush(struct ieee80211_sub_if_data *sdata) 839static void table_flush_by_iface(struct mesh_table *tbl,
840 struct ieee80211_sub_if_data *sdata)
825{ 841{
826 struct mesh_table *tbl;
827 struct mesh_path *mpath; 842 struct mesh_path *mpath;
828 struct mpath_node *node; 843 struct mpath_node *node;
829 struct hlist_node *p; 844 struct hlist_node *p;
830 int i; 845 int i;
831 846
832 rcu_read_lock(); 847 WARN_ON(!rcu_read_lock_held());
833 tbl = rcu_dereference(mesh_paths);
834 for_each_mesh_entry(tbl, p, node, i) { 848 for_each_mesh_entry(tbl, p, node, i) {
835 mpath = node->mpath; 849 mpath = node->mpath;
836 if (mpath->sdata == sdata) 850 if (mpath->sdata != sdata)
837 mesh_path_del(mpath->dst, mpath->sdata); 851 continue;
852 spin_lock_bh(&tbl->hashwlock[i]);
853 __mesh_path_del(tbl, node);
854 spin_unlock_bh(&tbl->hashwlock[i]);
838 } 855 }
839 rcu_read_unlock();
840} 856}
841 857
842static void mesh_path_node_reclaim(struct rcu_head *rp) 858/**
859 * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface
860 *
861 * This function deletes both mesh paths as well as mesh portal paths.
862 *
863 * @sdata - interface data to match
864 *
865 */
866void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
843{ 867{
844 struct mpath_node *node = container_of(rp, struct mpath_node, rcu); 868 struct mesh_table *tbl;
845 struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
846 869
847 del_timer_sync(&node->mpath->timer); 870 rcu_read_lock();
848 atomic_dec(&sdata->u.mesh.mpaths); 871 read_lock_bh(&pathtbl_resize_lock);
849 kfree(node->mpath); 872 tbl = resize_dereference_mesh_paths();
850 kfree(node); 873 table_flush_by_iface(tbl, sdata);
874 tbl = resize_dereference_mpp_paths();
875 table_flush_by_iface(tbl, sdata);
876 read_unlock_bh(&pathtbl_resize_lock);
877 rcu_read_unlock();
851} 878}
852 879
853/** 880/**
@@ -878,14 +905,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
878 mpath = node->mpath; 905 mpath = node->mpath;
879 if (mpath->sdata == sdata && 906 if (mpath->sdata == sdata &&
880 memcmp(addr, mpath->dst, ETH_ALEN) == 0) { 907 memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
881 spin_lock_bh(&mpath->state_lock); 908 __mesh_path_del(tbl, node);
882 if (mpath->is_gate)
883 mesh_gate_del(tbl, mpath);
884 mpath->flags |= MESH_PATH_RESOLVING;
885 hlist_del_rcu(&node->list);
886 call_rcu(&node->rcu, mesh_path_node_reclaim);
887 atomic_dec(&tbl->entries);
888 spin_unlock_bh(&mpath->state_lock);
889 goto enddel; 909 goto enddel;
890 } 910 }
891 } 911 }
@@ -991,9 +1011,14 @@ void mesh_path_discard_frame(struct sk_buff *skb,
991 1011
992 da = hdr->addr3; 1012 da = hdr->addr3;
993 ra = hdr->addr1; 1013 ra = hdr->addr1;
1014 rcu_read_lock();
994 mpath = mesh_path_lookup(da, sdata); 1015 mpath = mesh_path_lookup(da, sdata);
995 if (mpath) 1016 if (mpath) {
1017 spin_lock_bh(&mpath->state_lock);
996 sn = ++mpath->sn; 1018 sn = ++mpath->sn;
1019 spin_unlock_bh(&mpath->state_lock);
1020 }
1021 rcu_read_unlock();
997 mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data, 1022 mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
998 cpu_to_le32(sn), reason, ra, sdata); 1023 cpu_to_le32(sn), reason, ra, sdata);
999 } 1024 }
@@ -1074,6 +1099,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
1074int mesh_pathtbl_init(void) 1099int mesh_pathtbl_init(void)
1075{ 1100{
1076 struct mesh_table *tbl_path, *tbl_mpp; 1101 struct mesh_table *tbl_path, *tbl_mpp;
1102 int ret;
1077 1103
1078 tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); 1104 tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
1079 if (!tbl_path) 1105 if (!tbl_path)
@@ -1082,18 +1108,26 @@ int mesh_pathtbl_init(void)
1082 tbl_path->copy_node = &mesh_path_node_copy; 1108 tbl_path->copy_node = &mesh_path_node_copy;
1083 tbl_path->mean_chain_len = MEAN_CHAIN_LEN; 1109 tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
1084 tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); 1110 tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
1111 if (!tbl_path->known_gates) {
1112 ret = -ENOMEM;
1113 goto free_path;
1114 }
1085 INIT_HLIST_HEAD(tbl_path->known_gates); 1115 INIT_HLIST_HEAD(tbl_path->known_gates);
1086 1116
1087 1117
1088 tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); 1118 tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
1089 if (!tbl_mpp) { 1119 if (!tbl_mpp) {
1090 mesh_table_free(tbl_path, true); 1120 ret = -ENOMEM;
1091 return -ENOMEM; 1121 goto free_path;
1092 } 1122 }
1093 tbl_mpp->free_node = &mesh_path_node_free; 1123 tbl_mpp->free_node = &mesh_path_node_free;
1094 tbl_mpp->copy_node = &mesh_path_node_copy; 1124 tbl_mpp->copy_node = &mesh_path_node_copy;
1095 tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN; 1125 tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
1096 tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); 1126 tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
1127 if (!tbl_mpp->known_gates) {
1128 ret = -ENOMEM;
1129 goto free_mpp;
1130 }
1097 INIT_HLIST_HEAD(tbl_mpp->known_gates); 1131 INIT_HLIST_HEAD(tbl_mpp->known_gates);
1098 1132
1099 /* Need no locking since this is during init */ 1133 /* Need no locking since this is during init */
@@ -1101,6 +1135,12 @@ int mesh_pathtbl_init(void)
1101 RCU_INIT_POINTER(mpp_paths, tbl_mpp); 1135 RCU_INIT_POINTER(mpp_paths, tbl_mpp);
1102 1136
1103 return 0; 1137 return 0;
1138
1139free_mpp:
1140 mesh_table_free(tbl_mpp, true);
1141free_path:
1142 mesh_table_free(tbl_path, true);
1143 return ret;
1104} 1144}
1105 1145
1106void mesh_path_expire(struct ieee80211_sub_if_data *sdata) 1146void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
@@ -1117,14 +1157,10 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
1117 if (node->mpath->sdata != sdata) 1157 if (node->mpath->sdata != sdata)
1118 continue; 1158 continue;
1119 mpath = node->mpath; 1159 mpath = node->mpath;
1120 spin_lock_bh(&mpath->state_lock);
1121 if ((!(mpath->flags & MESH_PATH_RESOLVING)) && 1160 if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
1122 (!(mpath->flags & MESH_PATH_FIXED)) && 1161 (!(mpath->flags & MESH_PATH_FIXED)) &&
1123 time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) { 1162 time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
1124 spin_unlock_bh(&mpath->state_lock);
1125 mesh_path_del(mpath->dst, mpath->sdata); 1163 mesh_path_del(mpath->dst, mpath->sdata);
1126 } else
1127 spin_unlock_bh(&mpath->state_lock);
1128 } 1164 }
1129 rcu_read_unlock(); 1165 rcu_read_unlock();
1130} 1166}