aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_plink.c
diff options
context:
space:
mode:
authorThomas Pedersen <thomas@cozybit.com>2013-01-23 15:18:12 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-24 10:03:34 -0500
commit296fcba3ba1b8888aa8f5211de1e25a78b47aeee (patch)
treea8bb05498d62558513074cd6ded9975f2f2a5043 /net/mac80211/mesh_plink.c
parentd437c86baacf265a640dfc462c75941d02c0e153 (diff)
mac80211: clean up mesh sta allocation warning
This refactoring fixes a "scheduling while atomic" warning when allocating a mesh station entry while holding the RCU read lock. Fix this by creating a new function mesh_sta_info_get(), which correctly handles the locking and returns under RCU. Also move some unnecessarily #ifdefed mesh station init code from sta_info_alloc() to __mesh_sta_info_alloc(). Signed-off-by: Thomas Pedersen <thomas@cozybit.com> [change code flow to make sparse happy] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r--net/mac80211/mesh_plink.c158
1 files changed, 95 insertions, 63 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 9e0416696a83..ef92d2705851 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -55,30 +55,6 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
55 sta->plink_retries = 0; 55 sta->plink_retries = 0;
56} 56}
57 57
58/*
59 * Allocate mesh sta entry and insert into station table
60 */
61static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
62 u8 *hw_addr)
63{
64 struct sta_info *sta;
65
66 if (sdata->local->num_sta >= MESH_MAX_PLINKS)
67 return NULL;
68
69 sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
70 if (!sta)
71 return NULL;
72
73 sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
74 sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
75 sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
76
77 set_sta_flag(sta, WLAN_STA_WME);
78
79 return sta;
80}
81
82/** 58/**
83 * mesh_set_ht_prot_mode - set correct HT protection mode 59 * mesh_set_ht_prot_mode - set correct HT protection mode
84 * 60 *
@@ -309,52 +285,24 @@ free:
309 return err; 285 return err;
310} 286}
311 287
312/** 288static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
313 * mesh_peer_init - initialize new mesh peer and return resulting sta_info 289 struct sta_info *sta,
314 * 290 struct ieee802_11_elems *elems, bool insert)
315 * @sdata: local meshif
316 * @addr: peer's address
317 * @elems: IEs from beacon or mesh peering frame
318 *
319 * call under RCU
320 */
321static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
322 u8 *addr,
323 struct ieee802_11_elems *elems)
324{ 291{
325 struct ieee80211_local *local = sdata->local; 292 struct ieee80211_local *local = sdata->local;
326 enum ieee80211_band band = ieee80211_get_sdata_band(sdata); 293 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
327 struct ieee80211_supported_band *sband; 294 struct ieee80211_supported_band *sband;
328 u32 rates, basic_rates = 0; 295 u32 rates, basic_rates = 0;
329 struct sta_info *sta;
330 bool insert = false;
331 296
332 sband = local->hw.wiphy->bands[band]; 297 sband = local->hw.wiphy->bands[band];
333 rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); 298 rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
334 299
335 sta = sta_info_get(sdata, addr);
336 if (!sta) {
337 /* Userspace handles peer allocation when security is enabled */
338 if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
339 cfg80211_notify_new_peer_candidate(sdata->dev, addr,
340 elems->ie_start,
341 elems->total_len,
342 GFP_ATOMIC);
343 return NULL;
344 }
345
346 sta = mesh_plink_alloc(sdata, addr);
347 if (!sta)
348 return NULL;
349 insert = true;
350 }
351
352 spin_lock_bh(&sta->lock); 300 spin_lock_bh(&sta->lock);
353 sta->last_rx = jiffies; 301 sta->last_rx = jiffies;
354 if (sta->plink_state == NL80211_PLINK_ESTAB) { 302
355 spin_unlock_bh(&sta->lock); 303 /* rates and capabilities don't change during peering */
356 return sta; 304 if (sta->plink_state == NL80211_PLINK_ESTAB)
357 } 305 goto out;
358 306
359 sta->sta.supp_rates[band] = rates; 307 sta->sta.supp_rates[band] = rates;
360 if (elems->ht_cap_elem && 308 if (elems->ht_cap_elem &&
@@ -379,22 +327,104 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
379 327
380 if (insert) 328 if (insert)
381 rate_control_rate_init(sta); 329 rate_control_rate_init(sta);
330out:
382 spin_unlock_bh(&sta->lock); 331 spin_unlock_bh(&sta->lock);
332}
333
334static struct sta_info *
335__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
336{
337 struct sta_info *sta;
383 338
384 if (insert && sta_info_insert(sta)) 339 if (sdata->local->num_sta >= MESH_MAX_PLINKS)
385 return NULL; 340 return NULL;
386 341
342 sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
343 if (!sta)
344 return NULL;
345
346 sta->plink_state = NL80211_PLINK_LISTEN;
347 init_timer(&sta->plink_timer);
348
349 sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
350 sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
351 sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
352
353 set_sta_flag(sta, WLAN_STA_WME);
354
355 return sta;
356}
357
358static struct sta_info *
359mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
360 struct ieee802_11_elems *elems)
361{
362 struct sta_info *sta = NULL;
363
364 /* Userspace handles peer allocation when security is enabled */
365 if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
366 cfg80211_notify_new_peer_candidate(sdata->dev, addr,
367 elems->ie_start,
368 elems->total_len,
369 GFP_KERNEL);
370 else
371 sta = __mesh_sta_info_alloc(sdata, addr);
372
387 return sta; 373 return sta;
388} 374}
389 375
376/*
377 * mesh_sta_info_get - return mesh sta info entry for @addr.
378 *
379 * @sdata: local meshif
380 * @addr: peer's address
381 * @elems: IEs from beacon or mesh peering frame.
382 *
383 * Return existing or newly allocated sta_info under RCU read lock.
384 * (re)initialize with given IEs.
385 */
386static struct sta_info *
387mesh_sta_info_get(struct ieee80211_sub_if_data *sdata,
388 u8 *addr, struct ieee802_11_elems *elems) __acquires(RCU)
389{
390 struct sta_info *sta = NULL;
391
392 rcu_read_lock();
393 sta = sta_info_get(sdata, addr);
394 if (sta) {
395 mesh_sta_info_init(sdata, sta, elems, false);
396 } else {
397 rcu_read_unlock();
398 /* can't run atomic */
399 sta = mesh_sta_info_alloc(sdata, addr, elems);
400 if (!sta) {
401 rcu_read_lock();
402 return NULL;
403 }
404
405 if (sta_info_insert_rcu(sta))
406 return NULL;
407 }
408
409 return sta;
410}
411
412/*
413 * mesh_neighbour_update - update or initialize new mesh neighbor.
414 *
415 * @sdata: local meshif
416 * @addr: peer's address
417 * @elems: IEs from beacon or mesh peering frame
418 *
419 * Initiates peering if appropriate.
420 */
390void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, 421void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
391 u8 *hw_addr, 422 u8 *hw_addr,
392 struct ieee802_11_elems *elems) 423 struct ieee802_11_elems *elems)
393{ 424{
394 struct sta_info *sta; 425 struct sta_info *sta;
395 426
396 rcu_read_lock(); 427 sta = mesh_sta_info_get(sdata, hw_addr, elems);
397 sta = mesh_peer_init(sdata, hw_addr, elems);
398 if (!sta) 428 if (!sta)
399 goto out; 429 goto out;
400 430
@@ -632,6 +662,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
632 (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) 662 (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
633 memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); 663 memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
634 664
665 /* WARNING: Only for sta pointer, is dropped & re-acquired */
635 rcu_read_lock(); 666 rcu_read_lock();
636 667
637 sta = sta_info_get(sdata, mgmt->sa); 668 sta = sta_info_get(sdata, mgmt->sa);
@@ -735,8 +766,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
735 } 766 }
736 767
737 if (event == OPN_ACPT) { 768 if (event == OPN_ACPT) {
769 rcu_read_unlock();
738 /* allocate sta entry if necessary and update info */ 770 /* allocate sta entry if necessary and update info */
739 sta = mesh_peer_init(sdata, mgmt->sa, &elems); 771 sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);
740 if (!sta) { 772 if (!sta) {
741 mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); 773 mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
742 rcu_read_unlock(); 774 rcu_read_unlock();