aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_plink.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:47 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:47 -0500
commit73651ee6396c499ccb59ebc84c9274db01ed026d (patch)
tree1d59027cbdaec732f3e1378770cbf7b42b48cd70 /net/mac80211/mesh_plink.c
parentd0709a65181beb787ef3f58cfe45536a2bb254c8 (diff)
mac80211: split sta_info_add
sta_info_add() has two functions: allocating a station info structure and inserting it into the hash table/list. Splitting these two functions allows allocating with GFP_KERNEL in many places instead of GFP_ATOMIC which is now required by the RCU protection. Additionally, in many places RCU protection is now no longer needed at all because between sta_info_alloc() and sta_info_insert() the caller owns the structure. This fixes a few race conditions with setting initial flags and similar, but not all (see comments in ieee80211_sta.c and cfg.c). More documentation on the existing races will be in a follow-up patch. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r--net/mac80211/mesh_plink.c43
1 files changed, 25 insertions, 18 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c2b80500ae72..85cb75d53c43 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -89,44 +89,41 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
89} 89}
90 90
91/** 91/**
92 * mesh_plink_add - allocate and add a new mesh peer link 92 * mesh_plink_alloc - allocate a new mesh peer link
93 * 93 *
94 * @sdata: local mesh interface
94 * @hw_addr: hardware address (ETH_ALEN length) 95 * @hw_addr: hardware address (ETH_ALEN length)
95 * @rates: rates the mesh peer supports 96 * @rates: rates the mesh peer supports
96 * @dev: local mesh interface
97 * 97 *
98 * The initial state of the new plink is set to LISTEN 98 * The initial state of the new plink is set to LISTEN
99 * 99 *
100 * Returns: non-NULL on success, ERR_PTR() on error. 100 * Returns: NULL on error.
101 */ 101 */
102struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, 102struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
103 struct ieee80211_sub_if_data *sdata) 103 u8 *hw_addr, u64 rates, gfp_t gfp)
104{ 104{
105 struct ieee80211_local *local = sdata->local; 105 struct ieee80211_local *local = sdata->local;
106 struct sta_info *sta; 106 struct sta_info *sta;
107 107
108 if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0) 108 if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0)
109 /* never add ourselves as neighbours */ 109 /* never add ourselves as neighbours */
110 return ERR_PTR(-EINVAL); 110 return NULL;
111 111
112 if (is_multicast_ether_addr(hw_addr)) 112 if (is_multicast_ether_addr(hw_addr))
113 return ERR_PTR(-EINVAL); 113 return NULL;
114 114
115 if (local->num_sta >= MESH_MAX_PLINKS) 115 if (local->num_sta >= MESH_MAX_PLINKS)
116 return ERR_PTR(-ENOSPC); 116 return NULL;
117 117
118 sta = sta_info_add(sdata, hw_addr); 118 sta = sta_info_alloc(sdata, hw_addr, gfp);
119 if (IS_ERR(sta)) 119 if (!sta)
120 return sta; 120 return NULL;
121 121
122 sta->plink_state = LISTEN; 122 sta->plink_state = LISTEN;
123 spin_lock_init(&sta->plink_lock); 123 spin_lock_init(&sta->plink_lock);
124 init_timer(&sta->plink_timer); 124 init_timer(&sta->plink_timer);
125 sta->flags |= WLAN_STA_AUTHORIZED; 125 sta->flags |= WLAN_STA_AUTHORIZED;
126 sta->supp_rates[local->hw.conf.channel->band] = rates; 126 sta->supp_rates[local->hw.conf.channel->band] = rates;
127 rate_control_rate_init(sta, local);
128
129 mesh_accept_plinks_update(sdata);
130 127
131 return sta; 128 return sta;
132} 129}
@@ -252,8 +249,13 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
252 249
253 sta = sta_info_get(local, hw_addr); 250 sta = sta_info_get(local, hw_addr);
254 if (!sta) { 251 if (!sta) {
255 sta = mesh_plink_add(hw_addr, rates, sdata); 252 sta = mesh_plink_alloc(sdata, hw_addr, rates, GFP_ATOMIC);
256 if (IS_ERR(sta)) { 253 if (!sta) {
254 rcu_read_unlock();
255 return;
256 }
257 if (sta_info_insert(sta)) {
258 sta_info_destroy(sta);
257 rcu_read_unlock(); 259 rcu_read_unlock();
258 return; 260 return;
259 } 261 }
@@ -516,12 +518,17 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
516 } 518 }
517 519
518 rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); 520 rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
519 sta = mesh_plink_add(mgmt->sa, rates, sdata); 521 sta = mesh_plink_alloc(sdata, mgmt->sa, rates, GFP_ATOMIC);
520 if (IS_ERR(sta)) { 522 if (!sta) {
521 mpl_dbg("Mesh plink error: plink table full\n"); 523 mpl_dbg("Mesh plink error: plink table full\n");
522 rcu_read_unlock(); 524 rcu_read_unlock();
523 return; 525 return;
524 } 526 }
527 if (sta_info_insert(sta)) {
528 sta_info_destroy(sta);
529 rcu_read_unlock();
530 return;
531 }
525 event = OPN_ACPT; 532 event = OPN_ACPT;
526 spin_lock_bh(&sta->plink_lock); 533 spin_lock_bh(&sta->plink_lock);
527 } else { 534 } else {