|
@@ -499,6 +499,96 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
|
|
|
return ieee80211_ibss_finish_sta(sta);
|
|
|
}
|
|
|
|
|
|
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
|
|
+{
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ int active = 0;
|
|
|
+ struct sta_info *sta;
|
|
|
+
|
|
|
+ sdata_assert_lock(sdata);
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+
|
|
|
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
|
|
+ if (sta->sdata == sdata &&
|
|
|
+ time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
|
|
|
+ jiffies)) {
|
|
|
+ active++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
+ return active;
|
|
|
+}
|
|
|
+
|
|
|
+static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
|
|
|
+{
|
|
|
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
|
|
+ struct ieee80211_local *local = sdata->local;
|
|
|
+ struct cfg80211_bss *cbss;
|
|
|
+ struct beacon_data *presp;
|
|
|
+ struct sta_info *sta;
|
|
|
+ int active_ibss;
|
|
|
+ u16 capability;
|
|
|
+
|
|
|
+ active_ibss = ieee80211_sta_active_ibss(sdata);
|
|
|
+
|
|
|
+ if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
|
|
|
+ capability = WLAN_CAPABILITY_IBSS;
|
|
|
+
|
|
|
+ if (ifibss->privacy)
|
|
|
+ capability |= WLAN_CAPABILITY_PRIVACY;
|
|
|
+
|
|
|
+ cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
|
|
|
+ ifibss->bssid, ifibss->ssid,
|
|
|
+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
|
|
+ WLAN_CAPABILITY_PRIVACY,
|
|
|
+ capability);
|
|
|
+
|
|
|
+ if (cbss) {
|
|
|
+ cfg80211_unlink_bss(local->hw.wiphy, cbss);
|
|
|
+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
|
|
|
+
|
|
|
+ sta_info_flush(sdata);
|
|
|
+
|
|
|
+ spin_lock_bh(&ifibss->incomplete_lock);
|
|
|
+ while (!list_empty(&ifibss->incomplete_stations)) {
|
|
|
+ sta = list_first_entry(&ifibss->incomplete_stations,
|
|
|
+ struct sta_info, list);
|
|
|
+ list_del(&sta->list);
|
|
|
+ spin_unlock_bh(&ifibss->incomplete_lock);
|
|
|
+
|
|
|
+ sta_info_free(local, sta);
|
|
|
+ spin_lock_bh(&ifibss->incomplete_lock);
|
|
|
+ }
|
|
|
+ spin_unlock_bh(&ifibss->incomplete_lock);
|
|
|
+
|
|
|
+ netif_carrier_off(sdata->dev);
|
|
|
+
|
|
|
+ sdata->vif.bss_conf.ibss_joined = false;
|
|
|
+ sdata->vif.bss_conf.ibss_creator = false;
|
|
|
+ sdata->vif.bss_conf.enable_beacon = false;
|
|
|
+ sdata->vif.bss_conf.ssid_len = 0;
|
|
|
+
|
|
|
+ /* remove beacon */
|
|
|
+ presp = rcu_dereference_protected(ifibss->presp,
|
|
|
+ lockdep_is_held(&sdata->wdev.mtx));
|
|
|
+ RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
|
|
|
+ if (presp)
|
|
|
+ kfree_rcu(presp, rcu_head);
|
|
|
+
|
|
|
+ clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
|
|
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
|
|
+ BSS_CHANGED_IBSS);
|
|
|
+ ieee80211_vif_release_channel(sdata);
|
|
|
+}
|
|
|
+
|
|
|
static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
|
|
|
struct ieee80211_mgmt *mgmt,
|
|
|
size_t len)
|
|
@@ -775,30 +865,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
|
|
ieee80211_queue_work(&local->hw, &sdata->work);
|
|
|
}
|
|
|
|
|
|
-static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
|
|
-{
|
|
|
- struct ieee80211_local *local = sdata->local;
|
|
|
- int active = 0;
|
|
|
- struct sta_info *sta;
|
|
|
-
|
|
|
- sdata_assert_lock(sdata);
|
|
|
-
|
|
|
- rcu_read_lock();
|
|
|
-
|
|
|
- list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
|
|
- if (sta->sdata == sdata &&
|
|
|
- time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
|
|
|
- jiffies)) {
|
|
|
- active++;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- rcu_read_unlock();
|
|
|
-
|
|
|
- return active;
|
|
|
-}
|
|
|
-
|
|
|
static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
|
|
|
{
|
|
|
struct ieee80211_local *local = sdata->local;
|
|
@@ -1265,73 +1331,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|
|
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
|
|
{
|
|
|
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
|
|
- struct ieee80211_local *local = sdata->local;
|
|
|
- struct cfg80211_bss *cbss;
|
|
|
- u16 capability;
|
|
|
- int active_ibss;
|
|
|
- struct sta_info *sta;
|
|
|
- struct beacon_data *presp;
|
|
|
-
|
|
|
- active_ibss = ieee80211_sta_active_ibss(sdata);
|
|
|
-
|
|
|
- if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
|
|
|
- capability = WLAN_CAPABILITY_IBSS;
|
|
|
-
|
|
|
- if (ifibss->privacy)
|
|
|
- capability |= WLAN_CAPABILITY_PRIVACY;
|
|
|
|
|
|
- cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
|
|
|
- ifibss->bssid, ifibss->ssid,
|
|
|
- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
|
|
- WLAN_CAPABILITY_PRIVACY,
|
|
|
- capability);
|
|
|
-
|
|
|
- if (cbss) {
|
|
|
- cfg80211_unlink_bss(local->hw.wiphy, cbss);
|
|
|
- cfg80211_put_bss(local->hw.wiphy, cbss);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
|
|
|
- memset(ifibss->bssid, 0, ETH_ALEN);
|
|
|
+ ieee80211_ibss_disconnect(sdata);
|
|
|
ifibss->ssid_len = 0;
|
|
|
-
|
|
|
- sta_info_flush(sdata);
|
|
|
-
|
|
|
- spin_lock_bh(&ifibss->incomplete_lock);
|
|
|
- while (!list_empty(&ifibss->incomplete_stations)) {
|
|
|
- sta = list_first_entry(&ifibss->incomplete_stations,
|
|
|
- struct sta_info, list);
|
|
|
- list_del(&sta->list);
|
|
|
- spin_unlock_bh(&ifibss->incomplete_lock);
|
|
|
-
|
|
|
- sta_info_free(local, sta);
|
|
|
- spin_lock_bh(&ifibss->incomplete_lock);
|
|
|
- }
|
|
|
- spin_unlock_bh(&ifibss->incomplete_lock);
|
|
|
-
|
|
|
- netif_carrier_off(sdata->dev);
|
|
|
+ memset(ifibss->bssid, 0, ETH_ALEN);
|
|
|
|
|
|
/* remove beacon */
|
|
|
kfree(sdata->u.ibss.ie);
|
|
|
- presp = rcu_dereference_protected(ifibss->presp,
|
|
|
- lockdep_is_held(&sdata->wdev.mtx));
|
|
|
- RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
|
|
|
|
|
|
/* on the next join, re-program HT parameters */
|
|
|
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
|
|
|
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
|
|
|
|
|
|
- sdata->vif.bss_conf.ibss_joined = false;
|
|
|
- sdata->vif.bss_conf.ibss_creator = false;
|
|
|
- sdata->vif.bss_conf.enable_beacon = false;
|
|
|
- sdata->vif.bss_conf.ssid_len = 0;
|
|
|
- clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
|
|
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
|
|
- BSS_CHANGED_IBSS);
|
|
|
- ieee80211_vif_release_channel(sdata);
|
|
|
synchronize_rcu();
|
|
|
- kfree(presp);
|
|
|
|
|
|
skb_queue_purge(&sdata->skb_queue);
|
|
|
|