mac80211: start auth/assoc timeout on frame status

When sending authentication/association frames they
might take a bit of time to go out because we may
have to synchronise with the AP, in particular in
the case where it's really a P2P GO. In this case
the 200ms fixed timeout could potentially be too
short if the beacon interval is relatively large.

For drivers that report TX status we can do better.
Instead of starting the timeout directly, start it
only when the frame status arrives. Since then the
frame was out on the air, we can wait shorter (the
typical response time is supposed to be 30ms, wait
100ms.) Also, if the frame failed to be transmitted
try again right away instead of waiting.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2013-01-29 15:02:27 +01:00
parent 3ff9a827c6
commit 1672c0e319
7 changed files with 103 additions and 29 deletions

View File

@ -408,6 +408,9 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted * @IEEE80211_TX_INTFL_RETRANSMISSION: This frame is being retransmitted
* after TX status because the destination was asleep, it must not * after TX status because the destination was asleep, it must not
* be modified again (no seqno assignment, crypto, etc.) * be modified again (no seqno assignment, crypto, etc.)
* @IEEE80211_TX_INTFL_MLME_CONN_TX: This frame was transmitted by the MLME
* code for connection establishment, this indicates that its status
* should kick the MLME state machine.
* @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211 * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
* MLME command (internal to mac80211 to figure out whether to send TX * MLME command (internal to mac80211 to figure out whether to send TX
* status to user space) * status to user space)
@ -459,7 +462,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17), IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17),
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18), IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19), IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
/* hole at 20, use later */ IEEE80211_TX_INTFL_MLME_CONN_TX = BIT(20),
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21), IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
IEEE80211_TX_CTL_LDPC = BIT(22), IEEE80211_TX_CTL_LDPC = BIT(22),
IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24), IEEE80211_TX_CTL_STBC = BIT(23) | BIT(24),

View File

@ -302,7 +302,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
"TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
sdata->vif.addr, addr, sdata->u.ibss.bssid); sdata->vif.addr, addr, sdata->u.ibss.bssid);
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0, ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0,
addr, sdata->u.ibss.bssid, NULL, 0, 0); addr, sdata->u.ibss.bssid, NULL, 0, 0, 0);
} }
return sta; return sta;
} }
@ -422,7 +422,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
* has actually implemented this. * has actually implemented this.
*/ */
ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0, ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, 0, NULL, 0,
mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0); mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
} }
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,

View File

@ -415,6 +415,10 @@ struct ieee80211_if_managed {
bool beacon_crc_valid; bool beacon_crc_valid;
u32 beacon_crc; u32 beacon_crc;
bool status_acked;
bool status_received;
__le16 status_fc;
enum { enum {
IEEE80211_MFP_DISABLED, IEEE80211_MFP_DISABLED,
IEEE80211_MFP_OPTIONAL, IEEE80211_MFP_OPTIONAL,
@ -1284,6 +1288,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
__le16 fc, bool acked);
/* IBSS code */ /* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@ -1544,7 +1550,8 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status, u16 transaction, u16 auth_alg, u16 status,
u8 *extra, size_t extra_len, const u8 *bssid, u8 *extra, size_t extra_len, const u8 *bssid,
const u8 *da, const u8 *key, u8 key_len, u8 key_idx); const u8 *da, const u8 *key, u8 key_len, u8 key_idx,
u32 tx_flags);
void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, u16 stype, u16 reason, const u8 *bssid, u16 stype, u16 reason,
bool send_frame, u8 *frame_buf); bool send_frame, u8 *frame_buf);
@ -1561,7 +1568,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, const u8 *ie, size_t ie_len,
u32 ratemask, bool directed, bool no_cck, u32 ratemask, bool directed, u32 tx_flags,
struct ieee80211_channel *channel, bool scan); struct ieee80211_channel *channel, bool scan);
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,

View File

@ -30,11 +30,13 @@
#include "rate.h" #include "rate.h"
#include "led.h" #include "led.h"
#define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10)
#define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) #define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5)
#define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10)
#define IEEE80211_ASSOC_MAX_TRIES 3
static int max_nullfunc_tries = 2; static int max_nullfunc_tries = 2;
module_param(max_nullfunc_tries, int, 0644); module_param(max_nullfunc_tries, int, 0644);
@ -644,6 +646,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
drv_mgd_prepare_tx(local, sdata); drv_mgd_prepare_tx(local, sdata);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_INTFL_MLME_CONN_TX;
ieee80211_tx_skb(sdata, skb); ieee80211_tx_skb(sdata, skb);
} }
@ -1707,7 +1712,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
ssid_len = ssid[1]; ssid_len = ssid[1];
ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL,
0, (u32) -1, true, false, 0, (u32) -1, true, 0,
ifmgd->associated->channel, false); ifmgd->associated->channel, false);
rcu_read_unlock(); rcu_read_unlock();
} }
@ -1937,9 +1942,11 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len) struct ieee80211_mgmt *mgmt, size_t len)
{ {
struct ieee80211_local *local = sdata->local;
struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
u8 *pos; u8 *pos;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
u32 tx_flags = 0;
pos = mgmt->u.auth.variable; pos = mgmt->u.auth.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
@ -1947,11 +1954,14 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
return; return;
auth_data->expected_transaction = 4; auth_data->expected_transaction = 4;
drv_mgd_prepare_tx(sdata->local, sdata); drv_mgd_prepare_tx(sdata->local, sdata);
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, 3, auth_data->algorithm, 0, ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
elems.challenge - 2, elems.challenge_len + 2, elems.challenge - 2, elems.challenge_len + 2,
auth_data->bss->bssid, auth_data->bss->bssid, auth_data->bss->bssid, auth_data->bss->bssid,
auth_data->key, auth_data->key_len, auth_data->key, auth_data->key_len,
auth_data->key_idx); auth_data->key_idx, tx_flags);
} }
static enum rx_mgmt_action __must_check static enum rx_mgmt_action __must_check
@ -2869,12 +2879,17 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
u32 tx_flags = 0;
lockdep_assert_held(&ifmgd->mtx); lockdep_assert_held(&ifmgd->mtx);
if (WARN_ON_ONCE(!auth_data)) if (WARN_ON_ONCE(!auth_data))
return -EINVAL; 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++; auth_data->tries++;
if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) {
@ -2911,7 +2926,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
ieee80211_send_auth(sdata, trans, auth_data->algorithm, status, ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
auth_data->data, auth_data->data_len, auth_data->data, auth_data->data_len,
auth_data->bss->bssid, auth_data->bss->bssid,
auth_data->bss->bssid, NULL, 0, 0); auth_data->bss->bssid, NULL, 0, 0,
tx_flags);
} else { } else {
const u8 *ssidie; const u8 *ssidie;
@ -2930,13 +2946,15 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
* will not answer to direct packet in unassociated state. * will not answer to direct packet in unassociated state.
*/ */
ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1],
NULL, 0, (u32) -1, true, false, NULL, 0, (u32) -1, true, tx_flags,
auth_data->bss->channel, false); auth_data->bss->channel, false);
rcu_read_unlock(); rcu_read_unlock();
} }
auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) {
run_again(ifmgd, auth_data->timeout); auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
run_again(ifmgd, auth_data->timeout);
}
return 0; return 0;
} }
@ -2967,12 +2985,26 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
IEEE80211_ASSOC_MAX_TRIES); IEEE80211_ASSOC_MAX_TRIES);
ieee80211_send_assoc(sdata); ieee80211_send_assoc(sdata);
assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) {
run_again(&sdata->u.mgd, assoc_data->timeout); assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
run_again(&sdata->u.mgd, assoc_data->timeout);
}
return 0; return 0;
} }
void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
__le16 fc, bool acked)
{
struct ieee80211_local *local = sdata->local;
sdata->u.mgd.status_fc = fc;
sdata->u.mgd.status_acked = acked;
sdata->u.mgd.status_received = true;
ieee80211_queue_work(&local->hw, &sdata->work);
}
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
@ -2980,6 +3012,33 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
mutex_lock(&ifmgd->mtx); mutex_lock(&ifmgd->mtx);
if (ifmgd->status_received) {
__le16 fc = ifmgd->status_fc;
bool status_acked = ifmgd->status_acked;
ifmgd->status_received = false;
if (ifmgd->auth_data &&
(ieee80211_is_probe_req(fc) || ieee80211_is_auth(fc))) {
if (status_acked) {
ifmgd->auth_data->timeout =
jiffies + IEEE80211_AUTH_TIMEOUT_SHORT;
run_again(ifmgd, ifmgd->auth_data->timeout);
} else {
ifmgd->auth_data->timeout = jiffies - 1;
}
} else if (ifmgd->assoc_data &&
(ieee80211_is_assoc_req(fc) ||
ieee80211_is_reassoc_req(fc))) {
if (status_acked) {
ifmgd->assoc_data->timeout =
jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT;
run_again(ifmgd, ifmgd->assoc_data->timeout);
} else {
ifmgd->assoc_data->timeout = jiffies - 1;
}
}
}
if (ifmgd->auth_data && if (ifmgd->auth_data &&
time_after(jiffies, ifmgd->auth_data->timeout)) { time_after(jiffies, ifmgd->auth_data->timeout)) {
if (ifmgd->auth_data->done) { if (ifmgd->auth_data->done) {

View File

@ -389,7 +389,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
local->scan_req->ssids[i].ssid_len, local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len, local->scan_req->ie, local->scan_req->ie_len,
local->scan_req->rates[band], false, local->scan_req->rates[band], false,
local->scan_req->no_cck, local->scan_req->no_cck ?
IEEE80211_TX_CTL_NO_CCK_RATE : 0,
local->hw.conf.channel, true); local->hw.conf.channel, true);
/* /*

View File

@ -335,7 +335,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
if (dropped) if (dropped)
acked = false; acked = false;
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
IEEE80211_TX_INTFL_MLME_CONN_TX)) {
struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_sub_if_data *iter_sdata; struct ieee80211_sub_if_data *iter_sdata;
u64 cookie = (unsigned long)skb; u64 cookie = (unsigned long)skb;
@ -357,10 +358,13 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
sdata = rcu_dereference(local->p2p_sdata); sdata = rcu_dereference(local->p2p_sdata);
} }
if (!sdata) if (!sdata) {
skb->dev = NULL; skb->dev = NULL;
else if (ieee80211_is_nullfunc(hdr->frame_control) || } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
ieee80211_is_qos_nullfunc(hdr->frame_control)) { ieee80211_mgd_conn_tx_status(sdata, hdr->frame_control,
acked);
} else if (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
cfg80211_probe_status(sdata->dev, hdr->addr1, cfg80211_probe_status(sdata->dev, hdr->addr1,
cookie, acked, GFP_ATOMIC); cookie, acked, GFP_ATOMIC);
} else { } else {

View File

@ -1030,7 +1030,8 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status, u16 transaction, u16 auth_alg, u16 status,
u8 *extra, size_t extra_len, const u8 *da, u8 *extra, size_t extra_len, const u8 *da,
const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx) const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx,
u32 tx_flags)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
@ -1063,7 +1064,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
WARN_ON(err); WARN_ON(err);
} }
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
tx_flags;
ieee80211_tx_skb(sdata, skb); ieee80211_tx_skb(sdata, skb);
} }
@ -1277,7 +1279,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
const u8 *ssid, size_t ssid_len, const u8 *ssid, size_t ssid_len,
const u8 *ie, size_t ie_len, const u8 *ie, size_t ie_len,
u32 ratemask, bool directed, bool no_cck, u32 ratemask, bool directed, u32 tx_flags,
struct ieee80211_channel *channel, bool scan) struct ieee80211_channel *channel, bool scan)
{ {
struct sk_buff *skb; struct sk_buff *skb;
@ -1286,9 +1288,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
ssid, ssid_len, ssid, ssid_len,
ie, ie_len, directed); ie, ie_len, directed);
if (skb) { if (skb) {
if (no_cck) IEEE80211_SKB_CB(skb)->flags |= tx_flags;
IEEE80211_SKB_CB(skb)->flags |=
IEEE80211_TX_CTL_NO_CCK_RATE;
if (scan) if (scan)
ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band);
else else