aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorThomas Pedersen <thomas@cozybit.com>2012-04-18 22:23:42 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-23 15:34:07 -0400
commit54ab1ffb6cd94e5c013d61c192e78e30fdf25f8a (patch)
tree4ec8399914d37eb20d2231bb16cf5e7bdfc80eab /net/mac80211
parent75acd5a82afda30fb615335ff6c8e5f3a1ca5e83 (diff)
mac80211: refactor mesh peer initialization
This patch unifies the previous two paths toward mesh peer creation a bit. It also fixes a bug where a peer's changing rates or HT mode wouldn't register on leaving and then returning to the mesh with a sta entry still present. Also clean up locking and clear possibly stale ht cap. Signed-off-by: Thomas Pedersen <thomas@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/mesh_plink.c126
1 files changed, 72 insertions, 54 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 9c836e774fb..c3a0b0a4f97 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -82,20 +82,14 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
82} 82}
83 83
84/* 84/*
85 * NOTE: This is just an alias for sta_info_alloc(), see notes 85 * Allocate mesh sta entry and insert into station table
86 * on it in the lifecycle management section!
87 */ 86 */
88static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, 87static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
89 u8 *hw_addr, u32 rates, 88 u8 *hw_addr)
90 struct ieee802_11_elems *elems)
91{ 89{
92 struct ieee80211_local *local = sdata->local;
93 struct ieee80211_supported_band *sband;
94 struct sta_info *sta; 90 struct sta_info *sta;
95 91
96 sband = local->hw.wiphy->bands[local->oper_channel->band]; 92 if (sdata->local->num_sta >= MESH_MAX_PLINKS)
97
98 if (local->num_sta >= MESH_MAX_PLINKS)
99 return NULL; 93 return NULL;
100 94
101 sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); 95 sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
@@ -108,12 +102,8 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
108 102
109 set_sta_flag(sta, WLAN_STA_WME); 103 set_sta_flag(sta, WLAN_STA_WME);
110 104
111 sta->sta.supp_rates[local->hw.conf.channel->band] = rates; 105 if (sta_info_insert(sta))
112 if (elems->ht_cap_elem) 106 return NULL;
113 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
114 elems->ht_cap_elem,
115 &sta->sta.ht_cap);
116 rate_control_rate_init(sta);
117 107
118 return sta; 108 return sta;
119} 109}
@@ -274,43 +264,76 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
274 return 0; 264 return 0;
275} 265}
276 266
277void mesh_neighbour_update(u8 *hw_addr, u32 rates, 267/* mesh_peer_init - initialize new mesh peer and return resulting sta_info
278 struct ieee80211_sub_if_data *sdata, 268 *
279 struct ieee802_11_elems *elems) 269 * @sdata: local meshif
270 * @addr: peer's address
271 * @rates: station's supported rates
272 * @elems: IEs from beacon or mesh peering frame
273 *
274 * call under RCU
275 */
276static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
277 u8 *addr, u32 rates,
278 struct ieee802_11_elems *elems)
280{ 279{
281 struct ieee80211_local *local = sdata->local; 280 struct ieee80211_local *local = sdata->local;
281 struct ieee80211_supported_band *sband;
282 struct sta_info *sta; 282 struct sta_info *sta;
283 283
284 rcu_read_lock(); 284 sband = local->hw.wiphy->bands[local->oper_channel->band];
285 285
286 sta = sta_info_get(sdata, hw_addr); 286 sta = sta_info_get(sdata, addr);
287 if (!sta) { 287 if (!sta) {
288 rcu_read_unlock(); 288 sta = mesh_plink_alloc(sdata, addr);
289 /* Userspace handles peer allocation when security is enabled
290 * */
291 if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
292 cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
293 elems->ie_start, elems->total_len,
294 GFP_KERNEL);
295 else
296 sta = mesh_plink_alloc(sdata, hw_addr, rates, elems);
297 if (!sta) 289 if (!sta)
298 return; 290 return NULL;
299 if (sta_info_insert_rcu(sta)) {
300 rcu_read_unlock();
301 return;
302 }
303 } 291 }
304 292
293 spin_lock_bh(&sta->lock);
305 sta->last_rx = jiffies; 294 sta->last_rx = jiffies;
306 sta->sta.supp_rates[local->hw.conf.channel->band] = rates; 295 sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
296 if (elems->ht_cap_elem)
297 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
298 elems->ht_cap_elem,
299 &sta->sta.ht_cap);
300 else
301 memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
302
303 rate_control_rate_init(sta);
304 spin_unlock_bh(&sta->lock);
305
306 return sta;
307}
308
309void mesh_neighbour_update(u8 *hw_addr, u32 rates,
310 struct ieee80211_sub_if_data *sdata,
311 struct ieee802_11_elems *elems)
312{
313 struct sta_info *sta;
314
315 /* Userspace handles peer allocation when security is enabled */
316 if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
317 cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
318 elems->ie_start,
319 elems->total_len,
320 GFP_KERNEL);
321 return;
322 }
323
324 rcu_read_lock();
325 sta = mesh_peer_init(sdata, hw_addr, rates, elems);
326 if (!sta)
327 goto out;
328
307 if (mesh_peer_accepts_plinks(elems) && 329 if (mesh_peer_accepts_plinks(elems) &&
308 sta->plink_state == NL80211_PLINK_LISTEN && 330 sta->plink_state == NL80211_PLINK_LISTEN &&
309 sdata->u.mesh.accepting_plinks && 331 sdata->u.mesh.accepting_plinks &&
310 sdata->u.mesh.mshcfg.auto_open_plinks && 332 sdata->u.mesh.mshcfg.auto_open_plinks &&
311 rssi_threshold_check(sta, sdata)) 333 rssi_threshold_check(sta, sdata))
312 mesh_plink_open(sta); 334 mesh_plink_open(sta);
313 335
336out:
314 rcu_read_unlock(); 337 rcu_read_unlock();
315} 338}
316 339
@@ -587,26 +610,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
587 return; 610 return;
588 } else if (!sta) { 611 } else if (!sta) {
589 /* ftype == WLAN_SP_MESH_PEERING_OPEN */ 612 /* ftype == WLAN_SP_MESH_PEERING_OPEN */
590
591 rcu_read_unlock();
592
593 if (!mesh_plink_free_count(sdata)) { 613 if (!mesh_plink_free_count(sdata)) {
594 mpl_dbg("Mesh plink error: no more free plinks\n"); 614 mpl_dbg("Mesh plink error: no more free plinks\n");
595 return;
596 }
597 sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
598 if (!sta) {
599 mpl_dbg("Mesh plink error: plink table full\n");
600 return;
601 }
602 if (sta_info_insert_rcu(sta)) {
603 rcu_read_unlock(); 615 rcu_read_unlock();
604 return; 616 return;
605 } 617 }
606 event = OPN_ACPT; 618 event = OPN_ACPT;
607 spin_lock_bh(&sta->lock);
608 } else if (matches_local) { 619 } else if (matches_local) {
609 spin_lock_bh(&sta->lock);
610 switch (ftype) { 620 switch (ftype) {
611 case WLAN_SP_MESH_PEERING_OPEN: 621 case WLAN_SP_MESH_PEERING_OPEN:
612 if (!mesh_plink_free_count(sdata) || 622 if (!mesh_plink_free_count(sdata) ||
@@ -643,12 +653,19 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
643 break; 653 break;
644 default: 654 default:
645 mpl_dbg("Mesh plink: unknown frame subtype\n"); 655 mpl_dbg("Mesh plink: unknown frame subtype\n");
646 spin_unlock_bh(&sta->lock);
647 rcu_read_unlock(); 656 rcu_read_unlock();
648 return; 657 return;
649 } 658 }
650 } else { 659 }
651 spin_lock_bh(&sta->lock); 660
661 if (event == OPN_ACPT) {
662 /* allocate sta entry if necessary and update info */
663 sta = mesh_peer_init(sdata, mgmt->sa, rates, &elems);
664 if (!sta) {
665 mpl_dbg("Mesh plink: failed to init peer!\n");
666 rcu_read_unlock();
667 return;
668 }
652 } 669 }
653 670
654 mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", 671 mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
@@ -656,6 +673,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
656 le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), 673 le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
657 event); 674 event);
658 reason = 0; 675 reason = 0;
676 spin_lock_bh(&sta->lock);
659 switch (sta->plink_state) { 677 switch (sta->plink_state) {
660 /* spin_unlock as soon as state is updated at each case */ 678 /* spin_unlock as soon as state is updated at each case */
661 case NL80211_PLINK_LISTEN: 679 case NL80211_PLINK_LISTEN: