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 | |
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')
-rw-r--r-- | net/mac80211/ibss.c | 154 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 8 | ||||
-rw-r--r-- | net/mac80211/rx.c | 4 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 31 |
4 files changed, 140 insertions, 57 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 */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9516c3088fba..eca6063e287c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -482,6 +482,9 @@ struct ieee80211_if_ibss { | |||
482 | struct sk_buff __rcu *presp; | 482 | struct sk_buff __rcu *presp; |
483 | struct sk_buff *skb; | 483 | struct sk_buff *skb; |
484 | 484 | ||
485 | spinlock_t incomplete_lock; | ||
486 | struct list_head incomplete_stations; | ||
487 | |||
485 | enum { | 488 | enum { |
486 | IEEE80211_IBSS_MLME_SEARCH, | 489 | IEEE80211_IBSS_MLME_SEARCH, |
487 | IEEE80211_IBSS_MLME_JOINED, | 490 | IEEE80211_IBSS_MLME_JOINED, |
@@ -1172,9 +1175,8 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); | |||
1172 | /* IBSS code */ | 1175 | /* IBSS code */ |
1173 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1176 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
1174 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | 1177 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); |
1175 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 1178 | void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, |
1176 | u8 *bssid, u8 *addr, u32 supp_rates, | 1179 | const u8 *bssid, const u8 *addr, u32 supp_rates); |
1177 | gfp_t gfp); | ||
1178 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 1180 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
1179 | struct cfg80211_ibss_params *params); | 1181 | struct cfg80211_ibss_params *params); |
1180 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 1182 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7d226417ef46..2be5b7d69ad7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2775,8 +2775,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
2775 | rate_idx = 0; /* TODO: HT rates */ | 2775 | rate_idx = 0; /* TODO: HT rates */ |
2776 | else | 2776 | else |
2777 | rate_idx = status->rate_idx; | 2777 | rate_idx = status->rate_idx; |
2778 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, | 2778 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, |
2779 | hdr->addr2, BIT(rate_idx), GFP_ATOMIC); | 2779 | BIT(rate_idx)); |
2780 | } | 2780 | } |
2781 | break; | 2781 | break; |
2782 | case NL80211_IFTYPE_MESH_POINT: | 2782 | case NL80211_IFTYPE_MESH_POINT: |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 16de3bd16107..aa9293d7f3f0 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -354,35 +354,26 @@ static int sta_info_finish_insert(struct sta_info *sta, | |||
354 | /* notify driver */ | 354 | /* notify driver */ |
355 | err = drv_sta_add(local, sdata, &sta->sta); | 355 | err = drv_sta_add(local, sdata, &sta->sta); |
356 | if (err) { | 356 | if (err) { |
357 | if (!async) | 357 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) |
358 | return err; | 358 | return err; |
359 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " | 359 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " |
360 | "driver (%d) - keeping it anyway.\n", | 360 | "driver (%d) - keeping it anyway.\n", |
361 | sdata->name, sta->sta.addr, err); | 361 | sdata->name, sta->sta.addr, err); |
362 | } else { | 362 | } else |
363 | sta->uploaded = true; | 363 | sta->uploaded = true; |
364 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
365 | if (async) | ||
366 | wiphy_debug(local->hw.wiphy, | ||
367 | "Finished adding IBSS STA %pM\n", | ||
368 | sta->sta.addr); | ||
369 | #endif | ||
370 | } | ||
371 | 364 | ||
372 | sdata = sta->sdata; | 365 | sdata = sta->sdata; |
373 | } | 366 | } |
374 | 367 | ||
375 | if (!dummy_reinsert) { | 368 | if (!dummy_reinsert) { |
376 | if (!async) { | 369 | local->num_sta++; |
377 | local->num_sta++; | 370 | local->sta_generation++; |
378 | local->sta_generation++; | 371 | smp_mb(); |
379 | smp_mb(); | 372 | |
380 | 373 | /* make the station visible */ | |
381 | /* make the station visible */ | 374 | spin_lock_irqsave(&local->sta_lock, flags); |
382 | spin_lock_irqsave(&local->sta_lock, flags); | 375 | sta_info_hash_add(local, sta); |
383 | sta_info_hash_add(local, sta); | 376 | spin_unlock_irqrestore(&local->sta_lock, flags); |
384 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
385 | } | ||
386 | 377 | ||
387 | list_add(&sta->list, &local->sta_list); | 378 | list_add(&sta->list, &local->sta_list); |
388 | } else { | 379 | } else { |
@@ -1546,7 +1537,7 @@ EXPORT_SYMBOL(ieee80211_sta_set_buffered); | |||
1546 | int sta_info_move_state_checked(struct sta_info *sta, | 1537 | int sta_info_move_state_checked(struct sta_info *sta, |
1547 | enum ieee80211_sta_state new_state) | 1538 | enum ieee80211_sta_state new_state) |
1548 | { | 1539 | { |
1549 | /* might_sleep(); -- for driver notify later, fix IBSS first */ | 1540 | might_sleep(); |
1550 | 1541 | ||
1551 | if (sta->sta_state == new_state) | 1542 | if (sta->sta_state == new_state) |
1552 | return 0; | 1543 | return 0; |