diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-12-15 05:17:37 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-12-15 14:46:34 -0500 |
commit | 8bf11d8d081106c3cce8281a0150e716f8ac5d22 (patch) | |
tree | 2b026b9638f7acad90d4712f1675d80f3247a0d1 /net/mac80211/ibss.c | |
parent | 56544160d44c3043c0a7faffa506f616c1bb45f0 (diff) |
mac80211: delay IBSS station insertion
In order to notify drivers and simplify the station
management code, defer IBSS station insertion to a
work item and don't do it directly while receiving
a frame.
This increases the complexity in IBSS a little bit,
but it's pretty straight forward and it allows us
to reduce the station management complexity (next
patch) considerably.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 154 |
1 files changed, 122 insertions, 32 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 47e2db9133cb..f8a32bf98216 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -275,6 +275,80 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
275 | cbss->tsf); | 275 | cbss->tsf); |
276 | } | 276 | } |
277 | 277 | ||
278 | static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) | ||
279 | __acquires(RCU) | ||
280 | { | ||
281 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
282 | u8 addr[ETH_ALEN]; | ||
283 | |||
284 | memcpy(addr, sta->sta.addr, ETH_ALEN); | ||
285 | |||
286 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
287 | wiphy_debug(sdata->local->hw.wiphy, | ||
288 | "Adding new IBSS station %pM (dev=%s)\n", | ||
289 | addr, sdata->name); | ||
290 | #endif | ||
291 | |||
292 | sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
293 | sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
294 | sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
295 | |||
296 | rate_control_rate_init(sta); | ||
297 | |||
298 | /* If it fails, maybe we raced another insertion? */ | ||
299 | if (sta_info_insert_rcu(sta)) | ||
300 | return sta_info_get(sdata, addr); | ||
301 | return sta; | ||
302 | } | ||
303 | |||
304 | static struct sta_info * | ||
305 | ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
306 | const u8 *bssid, const u8 *addr, | ||
307 | u32 supp_rates) | ||
308 | __acquires(RCU) | ||
309 | { | ||
310 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
311 | struct ieee80211_local *local = sdata->local; | ||
312 | struct sta_info *sta; | ||
313 | int band = local->hw.conf.channel->band; | ||
314 | |||
315 | /* | ||
316 | * XXX: Consider removing the least recently used entry and | ||
317 | * allow new one to be added. | ||
318 | */ | ||
319 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
320 | if (net_ratelimit()) | ||
321 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", | ||
322 | sdata->name, addr); | ||
323 | rcu_read_lock(); | ||
324 | return NULL; | ||
325 | } | ||
326 | |||
327 | if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) { | ||
328 | rcu_read_lock(); | ||
329 | return NULL; | ||
330 | } | ||
331 | |||
332 | if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) { | ||
333 | rcu_read_lock(); | ||
334 | return NULL; | ||
335 | } | ||
336 | |||
337 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); | ||
338 | if (!sta) { | ||
339 | rcu_read_lock(); | ||
340 | return NULL; | ||
341 | } | ||
342 | |||
343 | sta->last_rx = jiffies; | ||
344 | |||
345 | /* make sure mandatory rates are always added */ | ||
346 | sta->sta.supp_rates[band] = supp_rates | | ||
347 | ieee80211_mandatory_rates(local, band); | ||
348 | |||
349 | return ieee80211_ibss_finish_sta(sta); | ||
350 | } | ||
351 | |||
278 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 352 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
279 | struct ieee80211_mgmt *mgmt, | 353 | struct ieee80211_mgmt *mgmt, |
280 | size_t len, | 354 | size_t len, |
@@ -334,10 +408,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
334 | #endif | 408 | #endif |
335 | rates_updated = true; | 409 | rates_updated = true; |
336 | } | 410 | } |
337 | } else | 411 | } else { |
412 | rcu_read_unlock(); | ||
338 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, | 413 | sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, |
339 | mgmt->sa, supp_rates, | 414 | mgmt->sa, supp_rates); |
340 | GFP_ATOMIC); | 415 | } |
341 | } | 416 | } |
342 | 417 | ||
343 | if (sta && elems->wmm_info) | 418 | if (sta && elems->wmm_info) |
@@ -464,21 +539,17 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
464 | ieee80211_sta_join_ibss(sdata, bss); | 539 | ieee80211_sta_join_ibss(sdata, bss); |
465 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | 540 | supp_rates = ieee80211_sta_get_rates(local, elems, band); |
466 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 541 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
467 | supp_rates, GFP_KERNEL); | 542 | supp_rates); |
543 | rcu_read_unlock(); | ||
468 | } | 544 | } |
469 | 545 | ||
470 | put_bss: | 546 | put_bss: |
471 | ieee80211_rx_bss_put(local, bss); | 547 | ieee80211_rx_bss_put(local, bss); |
472 | } | 548 | } |
473 | 549 | ||
474 | /* | 550 | void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, |
475 | * Add a new IBSS station, will also be called by the RX code when, | 551 | const u8 *bssid, const u8 *addr, |
476 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | 552 | u32 supp_rates) |
477 | * must be callable in atomic context. | ||
478 | */ | ||
479 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
480 | u8 *bssid, u8 *addr, u32 supp_rates, | ||
481 | gfp_t gfp) | ||
482 | { | 553 | { |
483 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 554 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
484 | struct ieee80211_local *local = sdata->local; | 555 | struct ieee80211_local *local = sdata->local; |
@@ -493,40 +564,29 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
493 | if (net_ratelimit()) | 564 | if (net_ratelimit()) |
494 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", | 565 | printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n", |
495 | sdata->name, addr); | 566 | sdata->name, addr); |
496 | return NULL; | 567 | return; |
497 | } | 568 | } |
498 | 569 | ||
499 | if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) | 570 | if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) |
500 | return NULL; | 571 | return; |
501 | 572 | ||
502 | if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) | 573 | if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) |
503 | return NULL; | 574 | return; |
504 | |||
505 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
506 | wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n", | ||
507 | addr, sdata->name); | ||
508 | #endif | ||
509 | 575 | ||
510 | sta = sta_info_alloc(sdata, addr, gfp); | 576 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
511 | if (!sta) | 577 | if (!sta) |
512 | return NULL; | 578 | return; |
513 | 579 | ||
514 | sta->last_rx = jiffies; | 580 | sta->last_rx = jiffies; |
515 | 581 | ||
516 | sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
517 | sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
518 | sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
519 | |||
520 | /* make sure mandatory rates are always added */ | 582 | /* make sure mandatory rates are always added */ |
521 | sta->sta.supp_rates[band] = supp_rates | | 583 | sta->sta.supp_rates[band] = supp_rates | |
522 | ieee80211_mandatory_rates(local, band); | 584 | ieee80211_mandatory_rates(local, band); |
523 | 585 | ||
524 | rate_control_rate_init(sta); | 586 | spin_lock(&ifibss->incomplete_lock); |
525 | 587 | list_add(&sta->list, &ifibss->incomplete_stations); | |
526 | /* If it fails, maybe we raced another insertion? */ | 588 | spin_unlock(&ifibss->incomplete_lock); |
527 | if (sta_info_insert(sta)) | 589 | ieee80211_queue_work(&local->hw, &sdata->work); |
528 | return sta_info_get(sdata, addr); | ||
529 | return sta; | ||
530 | } | 590 | } |
531 | 591 | ||
532 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | 592 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) |
@@ -865,6 +925,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
865 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | 925 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) |
866 | { | 926 | { |
867 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 927 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
928 | struct sta_info *sta; | ||
868 | 929 | ||
869 | mutex_lock(&ifibss->mtx); | 930 | mutex_lock(&ifibss->mtx); |
870 | 931 | ||
@@ -876,6 +937,19 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | |||
876 | if (!ifibss->ssid_len) | 937 | if (!ifibss->ssid_len) |
877 | goto out; | 938 | goto out; |
878 | 939 | ||
940 | spin_lock_bh(&ifibss->incomplete_lock); | ||
941 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
942 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
943 | struct sta_info, list); | ||
944 | list_del(&sta->list); | ||
945 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
946 | |||
947 | ieee80211_ibss_finish_sta(sta); | ||
948 | rcu_read_unlock(); | ||
949 | spin_lock_bh(&ifibss->incomplete_lock); | ||
950 | } | ||
951 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
952 | |||
879 | switch (ifibss->state) { | 953 | switch (ifibss->state) { |
880 | case IEEE80211_IBSS_MLME_SEARCH: | 954 | case IEEE80211_IBSS_MLME_SEARCH: |
881 | ieee80211_sta_find_ibss(sdata); | 955 | ieee80211_sta_find_ibss(sdata); |
@@ -934,6 +1008,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
934 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, | 1008 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, |
935 | (unsigned long) sdata); | 1009 | (unsigned long) sdata); |
936 | mutex_init(&ifibss->mtx); | 1010 | mutex_init(&ifibss->mtx); |
1011 | INIT_LIST_HEAD(&ifibss->incomplete_stations); | ||
1012 | spin_lock_init(&ifibss->incomplete_lock); | ||
937 | } | 1013 | } |
938 | 1014 | ||
939 | /* scan finished notification */ | 1015 | /* scan finished notification */ |
@@ -1053,6 +1129,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1053 | struct cfg80211_bss *cbss; | 1129 | struct cfg80211_bss *cbss; |
1054 | u16 capability; | 1130 | u16 capability; |
1055 | int active_ibss; | 1131 | int active_ibss; |
1132 | struct sta_info *sta; | ||
1056 | 1133 | ||
1057 | mutex_lock(&sdata->u.ibss.mtx); | 1134 | mutex_lock(&sdata->u.ibss.mtx); |
1058 | 1135 | ||
@@ -1081,6 +1158,19 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1081 | } | 1158 | } |
1082 | 1159 | ||
1083 | sta_info_flush(sdata->local, sdata); | 1160 | sta_info_flush(sdata->local, sdata); |
1161 | |||
1162 | spin_lock_bh(&ifibss->incomplete_lock); | ||
1163 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
1164 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
1165 | struct sta_info, list); | ||
1166 | list_del(&sta->list); | ||
1167 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
1168 | |||
1169 | sta_info_free(local, sta); | ||
1170 | spin_lock_bh(&ifibss->incomplete_lock); | ||
1171 | } | ||
1172 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
1173 | |||
1084 | netif_carrier_off(sdata->dev); | 1174 | netif_carrier_off(sdata->dev); |
1085 | 1175 | ||
1086 | /* remove beacon */ | 1176 | /* remove beacon */ |