diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-08-28 07:41:30 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-09-26 07:27:14 -0400 |
commit | 871a4180b8b62dbed54cd203c33bdab7fce24e6f (patch) | |
tree | c104bb4f569f18331df3bf3a293d4ecf31d9d620 /net/mac80211/ibss.c | |
parent | e6b7cde4d3e155f118b81f1f62f86554c529083a (diff) |
mac80211: split off ibss disconnect
IBSS CSA will require to disconnect if a channel switch fails, but
mac80211 should search and re-connect after this disconnect. To allow
such usage, split off the ibss disconnect process in a separate function
which only performs the disconnect without overwriting nl80211-supplied
parameters.
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 172 |
1 files changed, 92 insertions, 80 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index a12afe77bb26..0c3ec082e4f5 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -499,6 +499,96 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
499 | return ieee80211_ibss_finish_sta(sta); | 499 | return ieee80211_ibss_finish_sta(sta); |
500 | } | 500 | } |
501 | 501 | ||
502 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
503 | { | ||
504 | struct ieee80211_local *local = sdata->local; | ||
505 | int active = 0; | ||
506 | struct sta_info *sta; | ||
507 | |||
508 | sdata_assert_lock(sdata); | ||
509 | |||
510 | rcu_read_lock(); | ||
511 | |||
512 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
513 | if (sta->sdata == sdata && | ||
514 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
515 | jiffies)) { | ||
516 | active++; | ||
517 | break; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | rcu_read_unlock(); | ||
522 | |||
523 | return active; | ||
524 | } | ||
525 | |||
526 | static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) | ||
527 | { | ||
528 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
529 | struct ieee80211_local *local = sdata->local; | ||
530 | struct cfg80211_bss *cbss; | ||
531 | struct beacon_data *presp; | ||
532 | struct sta_info *sta; | ||
533 | int active_ibss; | ||
534 | u16 capability; | ||
535 | |||
536 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
537 | |||
538 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | ||
539 | capability = WLAN_CAPABILITY_IBSS; | ||
540 | |||
541 | if (ifibss->privacy) | ||
542 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
543 | |||
544 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | ||
545 | ifibss->bssid, ifibss->ssid, | ||
546 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
547 | WLAN_CAPABILITY_PRIVACY, | ||
548 | capability); | ||
549 | |||
550 | if (cbss) { | ||
551 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
552 | cfg80211_put_bss(sdata->local->hw.wiphy, cbss); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
557 | |||
558 | sta_info_flush(sdata); | ||
559 | |||
560 | spin_lock_bh(&ifibss->incomplete_lock); | ||
561 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
562 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
563 | struct sta_info, list); | ||
564 | list_del(&sta->list); | ||
565 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
566 | |||
567 | sta_info_free(local, sta); | ||
568 | spin_lock_bh(&ifibss->incomplete_lock); | ||
569 | } | ||
570 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
571 | |||
572 | netif_carrier_off(sdata->dev); | ||
573 | |||
574 | sdata->vif.bss_conf.ibss_joined = false; | ||
575 | sdata->vif.bss_conf.ibss_creator = false; | ||
576 | sdata->vif.bss_conf.enable_beacon = false; | ||
577 | sdata->vif.bss_conf.ssid_len = 0; | ||
578 | |||
579 | /* remove beacon */ | ||
580 | presp = rcu_dereference_protected(ifibss->presp, | ||
581 | lockdep_is_held(&sdata->wdev.mtx)); | ||
582 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | ||
583 | if (presp) | ||
584 | kfree_rcu(presp, rcu_head); | ||
585 | |||
586 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
587 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | ||
588 | BSS_CHANGED_IBSS); | ||
589 | ieee80211_vif_release_channel(sdata); | ||
590 | } | ||
591 | |||
502 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, | 592 | static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata, |
503 | struct ieee80211_mgmt *mgmt, | 593 | struct ieee80211_mgmt *mgmt, |
504 | size_t len) | 594 | size_t len) |
@@ -775,30 +865,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
775 | ieee80211_queue_work(&local->hw, &sdata->work); | 865 | ieee80211_queue_work(&local->hw, &sdata->work); |
776 | } | 866 | } |
777 | 867 | ||
778 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
779 | { | ||
780 | struct ieee80211_local *local = sdata->local; | ||
781 | int active = 0; | ||
782 | struct sta_info *sta; | ||
783 | |||
784 | sdata_assert_lock(sdata); | ||
785 | |||
786 | rcu_read_lock(); | ||
787 | |||
788 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
789 | if (sta->sdata == sdata && | ||
790 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
791 | jiffies)) { | ||
792 | active++; | ||
793 | break; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | rcu_read_unlock(); | ||
798 | |||
799 | return active; | ||
800 | } | ||
801 | |||
802 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) | 868 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) |
803 | { | 869 | { |
804 | struct ieee80211_local *local = sdata->local; | 870 | struct ieee80211_local *local = sdata->local; |
@@ -1265,73 +1331,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1265 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | 1331 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) |
1266 | { | 1332 | { |
1267 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 1333 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
1268 | struct ieee80211_local *local = sdata->local; | ||
1269 | struct cfg80211_bss *cbss; | ||
1270 | u16 capability; | ||
1271 | int active_ibss; | ||
1272 | struct sta_info *sta; | ||
1273 | struct beacon_data *presp; | ||
1274 | |||
1275 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
1276 | |||
1277 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | ||
1278 | capability = WLAN_CAPABILITY_IBSS; | ||
1279 | |||
1280 | if (ifibss->privacy) | ||
1281 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
1282 | 1334 | ||
1283 | cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan, | 1335 | ieee80211_ibss_disconnect(sdata); |
1284 | ifibss->bssid, ifibss->ssid, | ||
1285 | ifibss->ssid_len, WLAN_CAPABILITY_IBSS | | ||
1286 | WLAN_CAPABILITY_PRIVACY, | ||
1287 | capability); | ||
1288 | |||
1289 | if (cbss) { | ||
1290 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
1291 | cfg80211_put_bss(local->hw.wiphy, cbss); | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
1296 | memset(ifibss->bssid, 0, ETH_ALEN); | ||
1297 | ifibss->ssid_len = 0; | 1336 | ifibss->ssid_len = 0; |
1298 | 1337 | memset(ifibss->bssid, 0, ETH_ALEN); | |
1299 | sta_info_flush(sdata); | ||
1300 | |||
1301 | spin_lock_bh(&ifibss->incomplete_lock); | ||
1302 | while (!list_empty(&ifibss->incomplete_stations)) { | ||
1303 | sta = list_first_entry(&ifibss->incomplete_stations, | ||
1304 | struct sta_info, list); | ||
1305 | list_del(&sta->list); | ||
1306 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
1307 | |||
1308 | sta_info_free(local, sta); | ||
1309 | spin_lock_bh(&ifibss->incomplete_lock); | ||
1310 | } | ||
1311 | spin_unlock_bh(&ifibss->incomplete_lock); | ||
1312 | |||
1313 | netif_carrier_off(sdata->dev); | ||
1314 | 1338 | ||
1315 | /* remove beacon */ | 1339 | /* remove beacon */ |
1316 | kfree(sdata->u.ibss.ie); | 1340 | kfree(sdata->u.ibss.ie); |
1317 | presp = rcu_dereference_protected(ifibss->presp, | ||
1318 | lockdep_is_held(&sdata->wdev.mtx)); | ||
1319 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | ||
1320 | 1341 | ||
1321 | /* on the next join, re-program HT parameters */ | 1342 | /* on the next join, re-program HT parameters */ |
1322 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); | 1343 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); |
1323 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); | 1344 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); |
1324 | 1345 | ||
1325 | sdata->vif.bss_conf.ibss_joined = false; | ||
1326 | sdata->vif.bss_conf.ibss_creator = false; | ||
1327 | sdata->vif.bss_conf.enable_beacon = false; | ||
1328 | sdata->vif.bss_conf.ssid_len = 0; | ||
1329 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | ||
1330 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | ||
1331 | BSS_CHANGED_IBSS); | ||
1332 | ieee80211_vif_release_channel(sdata); | ||
1333 | synchronize_rcu(); | 1346 | synchronize_rcu(); |
1334 | kfree(presp); | ||
1335 | 1347 | ||
1336 | skb_queue_purge(&sdata->skb_queue); | 1348 | skb_queue_purge(&sdata->skb_queue); |
1337 | 1349 | ||