summaryrefslogtreecommitdiff
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c73
1 files changed, 57 insertions, 16 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 29620bfc7a6..a8c2130c8ba 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1015,7 +1015,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
static void
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- u64 timestamp, struct ieee802_11_elems *elems)
+ u64 timestamp, struct ieee802_11_elems *elems,
+ bool beacon)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1032,6 +1033,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def new_vht_chandef = {};
const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
+ const struct ieee80211_ht_operation *ht_oper;
int secondary_channel_offset = -1;
ASSERT_MGD_MTX(ifmgd);
@@ -1048,11 +1050,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sec_chan_offs = elems->sec_chan_offs;
wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
+ ht_oper = elems->ht_operation;
if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_40MHZ)) {
sec_chan_offs = NULL;
wide_bw_chansw_ie = NULL;
+ /* only used for bandwidth here */
+ ht_oper = NULL;
}
if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
@@ -1094,10 +1099,20 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return;
}
- if (sec_chan_offs) {
+ if (!beacon && sec_chan_offs) {
secondary_channel_offset = sec_chan_offs->sec_chan_offs;
+ } else if (beacon && ht_oper) {
+ secondary_channel_offset =
+ ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
} else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
- /* if HT is enabled and the IE not present, it's still HT */
+ /*
+ * If it's not a beacon, HT is enabled and the IE not present,
+ * it's 20 MHz, 802.11-2012 8.5.2.6:
+ * This element [the Secondary Channel Offset Element] is
+ * present when switching to a 40 MHz channel. It may be
+ * present when switching to a 20 MHz channel (in which
+ * case the secondary channel offset is set to SCN).
+ */
secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
}
@@ -2796,7 +2811,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->iflist_mtx);
}
- ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems);
+ ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+ elems, true);
}
@@ -3210,7 +3226,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_process_chanswitch(sdata,
rx_status->mactime,
- &elems);
+ &elems, false);
} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
ies_len = skb->len -
offsetof(struct ieee80211_mgmt,
@@ -3232,7 +3248,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
ieee80211_sta_process_chanswitch(sdata,
rx_status->mactime,
- &elems);
+ &elems, false);
}
break;
}
@@ -3305,10 +3321,6 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
if (WARN_ON_ONCE(!auth_data))
return -EINVAL;
- if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
- tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
- IEEE80211_TX_INTFL_MLME_CONN_TX;
-
auth_data->tries++;
if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
@@ -3342,6 +3354,10 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
auth_data->expected_transaction = trans;
}
+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+ tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
+ IEEE80211_TX_INTFL_MLME_CONN_TX;
+
ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
auth_data->data, auth_data->data_len,
auth_data->bss->bssid,
@@ -3365,12 +3381,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
* will not answer to direct packet in unassociated state.
*/
ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
- NULL, 0, (u32) -1, true, tx_flags,
+ NULL, 0, (u32) -1, true, 0,
auth_data->bss->channel, false);
rcu_read_unlock();
}
- if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) {
+ if (tx_flags == 0) {
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
ifmgd->auth_data->timeout_started = true;
run_again(ifmgd, auth_data->timeout);
@@ -3623,6 +3639,31 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
}
}
+#ifdef CONFIG_PM
+void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ mutex_lock(&ifmgd->mtx);
+ if (!ifmgd->associated) {
+ mutex_unlock(&ifmgd->mtx);
+ return;
+ }
+
+ if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
+ sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
+ mlme_dbg(sdata, "driver requested disconnect after resume\n");
+ ieee80211_sta_connection_lost(sdata,
+ ifmgd->associated->bssid,
+ WLAN_REASON_UNSPECIFIED,
+ true);
+ mutex_unlock(&ifmgd->mtx);
+ return;
+ }
+ mutex_unlock(&ifmgd->mtx);
+}
+#endif
+
/* interface setup */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
@@ -4329,7 +4370,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
bool tx = !req->local_state_change;
- bool sent_frame = false;
+ bool report_frame = false;
mutex_lock(&ifmgd->mtx);
@@ -4346,7 +4387,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_destroy_auth_data(sdata, false);
mutex_unlock(&ifmgd->mtx);
- sent_frame = tx;
+ report_frame = true;
goto out;
}
@@ -4354,12 +4395,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, frame_buf);
- sent_frame = tx;
+ report_frame = true;
}
mutex_unlock(&ifmgd->mtx);
out:
- if (sent_frame)
+ if (report_frame)
__cfg80211_send_deauth(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN);