Index: chromeos/compat-wireless/net/mac80211/mlme.c |
diff --git a/chromeos/compat-wireless/net/mac80211/mlme.c b/chromeos/compat-wireless/net/mac80211/mlme.c |
index 0c8510c49215263ed061a9e811311d0496fa4b20..a566a5c382270dd477d60fc0b26206064341712f 100644 |
--- a/chromeos/compat-wireless/net/mac80211/mlme.c |
+++ b/chromeos/compat-wireless/net/mac80211/mlme.c |
@@ -28,17 +28,19 @@ |
#include "rate.h" |
#include "led.h" |
-#define IEEE80211_MAX_PROBE_TRIES 1 |
+#define IEEE80211_MAX_NULLFUNC_TRIES 2 |
Sam Leffler
2010/12/08 18:37:56
until we can override upstream defaults w/o modify
|
+#define IEEE80211_MAX_PROBE_TRIES 5 |
/* |
- * beacon loss timeout is calculated as N frames times the |
+ * Beacon loss timeout is calculated as N frames times the |
* advertised beacon interval. This may need to be somewhat |
* higher than what hardware might detect to account for |
* delays in the host processing frames. But since we also |
- * probe on bmiss before declaring the connection lost default |
- * to what we want. |
+ * probe on beacon miss before declaring the connection lost |
+ * default to what we want. |
*/ |
-#define IEEE80211_BEACON_LOSS_COUNT 7 |
+#define IEEE80211_BEACON_LOSS_COUNT 7 |
+ |
/* |
* Time the connection can be idle before we probe |
* it to see if we can still talk to the AP. |
@@ -49,7 +51,7 @@ |
* a probe request because of beacon loss or for |
* checking the connection still works. |
*/ |
-#define IEEE80211_PROBE_WAIT (HZ / 5) |
+#define IEEE80211_PROBE_WAIT (HZ / 2) |
/* |
* Weight given to the latest Beacon frame when calculating average signal |
@@ -58,12 +60,6 @@ |
*/ |
#define IEEE80211_SIGNAL_AVE_WEIGHT 3 |
-/* |
- * How many Beacon frames need to have been used in average signal strength |
- * before starting to indicate signal change events. |
- */ |
-#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 |
- |
#define TMR_RUNNING_TIMER 0 |
#define TMR_RUNNING_CHANSW 1 |
@@ -125,7 +121,7 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) |
return; |
mod_timer(&sdata->u.mgd.bcn_mon_timer, |
- round_jiffies_up(jiffies + sdata->u.mgd.bloss_timeout)); |
+ round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); |
} |
void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) |
@@ -872,15 +868,15 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
bss_info_changed |= BSS_CHANGED_ASSOC; |
/* set timing information */ |
bss_conf->beacon_int = cbss->beacon_interval; |
- /* beacon_int is in TU, convert to jiffies for timer handling */ |
- sdata->u.mgd.bloss_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( |
- IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); |
bss_conf->timestamp = cbss->tsf; |
bss_info_changed |= BSS_CHANGED_BEACON_INT; |
bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
cbss->capability, bss->has_erp_value, bss->erp_value); |
+ sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( |
+ IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); |
+ |
sdata->u.mgd.associated = cbss; |
memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
@@ -1039,14 +1035,78 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
ieee80211_sta_reset_conn_monitor(sdata); |
} |
+static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) |
+{ |
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
+ |
+ if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
+ IEEE80211_STA_CONNECTION_POLL))) |
+ return; |
+ |
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
+ IEEE80211_STA_BEACON_POLL); |
+ mutex_lock(&sdata->local->iflist_mtx); |
+ ieee80211_recalc_ps(sdata->local, -1); |
+ mutex_unlock(&sdata->local->iflist_mtx); |
+ |
+ if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
+ return; |
+ |
+ /* |
+ * We've received a probe response, but are not sure whether |
+ * we have or will be receiving any beacons or data, so let's |
+ * schedule the timers again, just in case. |
+ */ |
+ ieee80211_sta_reset_beacon_monitor(sdata); |
+ |
+ mod_timer(&ifmgd->conn_mon_timer, |
+ round_jiffies_up(jiffies + |
+ IEEE80211_CONNECTION_IDLE_TIME)); |
+} |
+ |
+void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
+ struct ieee80211_hdr *hdr, bool ack) |
+{ |
+ if (!ieee80211_is_data(hdr->frame_control)) |
Sam Leffler
2010/12/08 18:37:56
this should check is_nullfunc instead and remove t
|
+ return; |
+ |
+ if (ack) |
+ ieee80211_sta_reset_conn_monitor(sdata); |
+ |
+ if (ieee80211_is_nullfunc(hdr->frame_control) && |
+ sdata->u.mgd.probe_send_count > 0) { |
+ if (ack) |
+ sdata->u.mgd.probe_send_count = 0; |
+ else |
+ sdata->u.mgd.nullfunc_failed = true; |
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
Sam Leffler
2010/12/08 18:37:56
this code is confusing because there are no commen
|
+ } |
+} |
+ |
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
{ |
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
const u8 *ssid; |
u8 *dst = ifmgd->associated->bssid; |
+ u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3); |
+ /* |
+ * Try sending broadcast probe requests for the last three |
+ * probe requests after the first ones failed since some |
+ * buggy APs only support broadcast probe requests. |
+ */ |
+ if (ifmgd->probe_send_count >= unicast_limit) |
+ dst = NULL; |
- if ((sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
+ /* |
+ * When the hardware reports an accurate Tx ACK status, it's |
+ * better to send a nullfunc frame instead of a probe request, |
+ * as it will kick us off the AP quickly if we aren't associated |
+ * anymore. The timeout will be reset if the frame is ACKed by |
+ * the AP. |
+ */ |
+ if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
+ ifmgd->nullfunc_failed = false; |
Sam Leffler
2010/12/08 18:37:56
it appears you are setting this here because the w
|
ieee80211_send_nullfunc(sdata->local, sdata, 0); |
} else { |
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); |
@@ -1054,6 +1114,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
} |
ifmgd->probe_send_count++; |
+ ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; |
+ run_again(ifmgd, ifmgd->probe_timeout); |
} |
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
@@ -1485,29 +1547,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, |
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
if (ifmgd->associated && |
- memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && |
- ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
- IEEE80211_STA_CONNECTION_POLL)) { |
- ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
- IEEE80211_STA_BEACON_POLL); |
- mutex_lock(&sdata->local->iflist_mtx); |
- ieee80211_recalc_ps(sdata->local, -1); |
- mutex_unlock(&sdata->local->iflist_mtx); |
- |
- if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
- return; |
- |
- /* |
- * We've received a probe response, but are not sure whether |
- * we have or will be receiving any beacons or data, so let's |
- * schedule the timers again, just in case. |
- */ |
- ieee80211_sta_reset_beacon_monitor(sdata); |
- |
- mod_timer(&ifmgd->conn_mon_timer, |
- round_jiffies_up(jiffies + |
- IEEE80211_CONNECTION_IDLE_TIME)); |
- } |
+ memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) |
+ ieee80211_reset_ap_probe(sdata); |
} |
/* |
@@ -1579,16 +1620,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; |
ifmgd->ave_beacon_signal = rx_status->signal * 16; |
ifmgd->last_cqm_event_signal = 0; |
- ifmgd->count_beacon_signal = 1; |
} else { |
ifmgd->ave_beacon_signal = |
(IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 + |
(16 - IEEE80211_SIGNAL_AVE_WEIGHT) * |
ifmgd->ave_beacon_signal) / 16; |
- ifmgd->count_beacon_signal++; |
} |
if (bss_conf->cqm_rssi_thold && |
- ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT && |
!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) { |
int sig = ifmgd->ave_beacon_signal / 16; |
int last_event = ifmgd->last_cqm_event_signal; |
@@ -1844,86 +1882,106 @@ static void ieee80211_sta_timer(unsigned long data) |
ieee80211_queue_work(&local->hw, &sdata->work); |
} |
-void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
+static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
+ u8 *bssid) |
{ |
- /* nothing right now */ |
+ struct ieee80211_local *local = sdata->local; |
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
+ |
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
+ IEEE80211_STA_BEACON_POLL); |
+ |
+ ieee80211_set_disassoc(sdata, true, true); |
+ ieee80211_recalc_idle(local); |
+ mutex_unlock(&ifmgd->mtx); |
+ /* |
+ * must be outside lock due to cfg80211, |
+ * but that's not a problem. |
+ */ |
+ ieee80211_send_deauth_disassoc(sdata, bssid, |
+ IEEE80211_STYPE_DEAUTH, |
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
+ NULL, true); |
+ mutex_lock(&ifmgd->mtx); |
} |
-static void ieee80211_sta_process_probe_status(struct ieee80211_sub_if_data *sdata) |
+void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
{ |
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
struct ieee80211_local *local = sdata->local; |
- u8 bssid[ETH_ALEN]; |
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
+ /* then process the rest of the work */ |
mutex_lock(&ifmgd->mtx); |
- if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
- IEEE80211_STA_CONNECTION_POLL))) |
- goto done; |
- if (!ifmgd->associated) /* XXX can this fail if flags are set? */ |
- goto done; |
- memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
- if (ifmgd->probe_acked) { |
- /* |
- * Probe frame was ACK'd, just clear polling state. |
- */ |
- ifmgd->flags &= ~(IEEE80211_STA_BEACON_POLL | |
- IEEE80211_STA_CONNECTION_POLL); |
- ifmgd->probe_send_count = 0; |
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
+ IEEE80211_STA_CONNECTION_POLL) && |
+ ifmgd->associated) { |
+ u8 bssid[ETH_ALEN]; |
+ int max_tries; |
- /* |
- * Re-enable power save |
- */ |
- mutex_lock(&local->iflist_mtx); |
- ieee80211_recalc_ps(local, -1); |
- mutex_unlock(&local->iflist_mtx); |
- } else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { |
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
- printk(KERN_DEBUG "No ACK of probe to AP %pM, try again (%d)\n", |
- bssid, ifmgd->probe_send_count); |
-#endif |
- ieee80211_mgd_probe_ap_send(sdata); |
- } else { |
- /* |
- * We actually lost the connection. |
- */ |
- ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | |
- IEEE80211_STA_BEACON_POLL); |
+ memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
- /* XXX juggle __ieee80211_connection_loss to suit */ |
- printk(KERN_DEBUG "No response from AP %pM, disconnecting.\n", |
- bssid); |
+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
+ max_tries = IEEE80211_MAX_NULLFUNC_TRIES; |
+ else |
+ max_tries = IEEE80211_MAX_PROBE_TRIES; |
Sam Leffler
2010/12/08 18:37:56
I find this combined code too complicated; I think
|
- ieee80211_set_disassoc(sdata, true, true); |
- ieee80211_recalc_idle(local); |
+ /* ACK received for nullfunc probing frame */ |
+ if (!ifmgd->probe_send_count) |
+ ieee80211_reset_ap_probe(sdata); |
+ else if (ifmgd->nullfunc_failed) { |
+ if (ifmgd->probe_send_count < max_tries) { |
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
+ wiphy_debug(local->hw.wiphy, |
+ "%s: No ack for nullfunc frame to" |
+ " AP %pM, try %d\n", |
+ sdata->name, bssid, |
+ ifmgd->probe_send_count); |
+#endif |
+ ieee80211_mgd_probe_ap_send(sdata); |
+ } else { |
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
+ wiphy_debug(local->hw.wiphy, |
+ "%s: No ack for nullfunc frame to" |
+ " AP %pM, disconnecting.\n", |
+ sdata->name, bssid, |
+ ifmgd->probe_send_count); |
+#endif |
+ ieee80211_sta_connection_lost(sdata, bssid); |
+ } |
+ } else if (time_is_after_jiffies(ifmgd->probe_timeout)) |
+ run_again(ifmgd, ifmgd->probe_timeout); |
+ else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
Sam Leffler
2010/12/08 18:37:56
how do we get to this case? If we have TX status
|
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
+ wiphy_debug(local->hw.wiphy, |
+ "%s: Failed to send nullfunc to AP %pM" |
+ " after %dms, disconnecting.\n", |
+ sdata->name, |
+ bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
+#endif |
+ ieee80211_sta_connection_lost(sdata, bssid); |
+ } else if (ifmgd->probe_send_count < max_tries) { |
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
+ printk(KERN_DEBUG "No probe response from AP %pM" |
+ " after %dms, try %d\n", bssid, |
+ (1000 * IEEE80211_PROBE_WAIT)/HZ, |
+ ifmgd->probe_send_count); |
+#endif |
+ ieee80211_mgd_probe_ap_send(sdata); |
+ } else { |
+ /* |
+ * We actually lost the connection ... or did we? |
+ * Let's make sure! |
+ */ |
+ printk(KERN_DEBUG "No probe response from AP %pM" |
+ " after %dms, disconnecting.\n", |
+ bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
- /* |
- * NB: must be outside lock due to cfg80211. |
- */ |
- mutex_unlock(&ifmgd->mtx); |
- ieee80211_send_deauth_disassoc(sdata, bssid, |
- IEEE80211_STYPE_DEAUTH, |
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
- NULL, true); |
- return; |
+ ieee80211_sta_connection_lost(sdata, bssid); |
+ } |
} |
-done: |
- mutex_unlock(&ifmgd->mtx); |
-} |
-/* |
- * Process TX status for probe frame sent to the associated |
- * AP on beacon or connection loss. |
- */ |
-static void ieee80211_probe_status_work(struct work_struct *work) |
-{ |
- struct ieee80211_sub_if_data *sdata = container_of(work, |
- struct ieee80211_sub_if_data, u.mgd.probe_status_work); |
- |
- WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION); |
- |
- if (ieee80211_sdata_running(sdata)) |
- ieee80211_sta_process_probe_status(sdata); |
+ mutex_unlock(&ifmgd->mtx); |
} |
static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -1967,6 +2025,9 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) |
sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | |
IEEE80211_STA_CONNECTION_POLL); |
+ /* let's probe the connection once */ |
+ ieee80211_queue_work(&sdata->local->hw, |
+ &sdata->u.mgd.monitor_work); |
/* and do all the other regular work too */ |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
} |
@@ -2005,9 +2066,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) |
add_timer(&ifmgd->timer); |
if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) |
add_timer(&ifmgd->chswitch_timer); |
- |
ieee80211_sta_reset_beacon_monitor(sdata); |
- ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); |
+ ieee80211_restart_sta_timer(sdata); |
} |
#endif |
@@ -2021,7 +2081,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
INIT_WORK(&ifmgd->beacon_connection_loss_work, |
ieee80211_beacon_connection_loss_work); |
- INIT_WORK(&ifmgd->probe_status_work, ieee80211_probe_status_work); |
INIT_WORK(&ifmgd->bitrate_notify_work, ieee80211_rate_notify_work); |
setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
(unsigned long) sdata); |