@@ -317,6 +317,7 @@ enum ieee80211_sta_flags {
IEEE80211_STA_MFP_ENABLED = BIT(6),
IEEE80211_STA_UAPSD_ENABLED = BIT(7),
IEEE80211_STA_NULLFUNC_ACKED = BIT(8),
+ IEEE80211_STA_CON_POLL_ACKED = BIT(9),
};
struct ieee80211_if_managed {
@@ -857,11 +857,16 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct ieee80211_local *local = sdata->local;
const u8 *ssid;
- ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
- ieee80211_send_probe_req(sdata, ifmgd->associated->bssid,
- ssid + 2, ssid[1], NULL, 0);
+ if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+ ieee80211_send_nullfunc(local, sdata, 0);
+ } else {
+ ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
+ ieee80211_send_probe_req(sdata, ifmgd->associated->bssid,
+ ssid + 2, ssid[1], NULL, 0);
+ }
ifmgd->probe_send_count++;
ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
@@ -1579,9 +1584,27 @@ static void ieee80211_sta_work(struct work_struct *work)
/* then process the rest of the work */
mutex_lock(&ifmgd->mtx);
- if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ if ((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
+ (ifmgd->flags & IEEE80211_STA_CON_POLL_ACKED)) {
+ /* FIXME: refactor with rx_mgmg_probe_resp() */
+ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
+ IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CON_POLL_ACKED);
+ mutex_lock(&sdata->local->iflist_mtx);
+ ieee80211_recalc_ps(sdata->local, -1);
+ mutex_unlock(&sdata->local->iflist_mtx);
+ /*
+ * 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.
+ */
+ mod_beacon_timer(sdata);
+ mod_timer(&ifmgd->conn_mon_timer,
+ round_jiffies_up(jiffies +
+ IEEE80211_CONNECTION_IDLE_TIME));
+ } else if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
IEEE80211_STA_CONNECTION_POLL) &&
- ifmgd->associated) {
+ ifmgd->associated) {
u8 bssid[ETH_ALEN];
memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
@@ -1590,7 +1613,7 @@ static void ieee80211_sta_work(struct work_struct *work)
else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- printk(KERN_DEBUG "No probe response from AP %pM"
+ printk(KERN_DEBUG "No response from AP %pM"
" after %dms, try %d\n", bssid,
(1000 * IEEE80211_PROBE_WAIT)/HZ,
ifmgd->probe_send_count);
@@ -1603,7 +1626,7 @@ static void ieee80211_sta_work(struct work_struct *work)
*/
ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
IEEE80211_STA_BEACON_POLL);
- printk(KERN_DEBUG "No probe response from AP %pM"
+ printk(KERN_DEBUG "No response from AP %pM"
" after %dms, disconnecting.\n",
bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
ieee80211_set_disassoc(sdata);
@@ -162,12 +162,58 @@ static void ieee80211_nullfunc_status(struct ieee80211_local *local,
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_managed *ifmgd;
__le16 fc = hdr->frame_control;
- if (ieee80211_has_pm(fc) &&
- (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
- !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
- local->ps_sdata && !(local->scanning)) {
+ if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
+ return;
+
+ if (info->flags & IEEE80211_TX_CTL_INJECTED)
+ return;
+
+ if (local->scanning)
+ return;
+
+ /* FIXME: check association? */
+
+ /*
+ * only executed when either 1) power save is enabled or 2) idle
+ * connection monitor is enabled, so this is definitely not in fast
+ * path and can be slow
+ */
+
+ /* connection tracking */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ continue;
+
+ ifmgd = &sdata->u.mgd;
+
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL)) {
+ printk(KERN_DEBUG "nullfunc %s\n",
+ (info->flags & IEEE80211_TX_STAT_ACK) ?
+ "acked" : "nacked");
+
+ if (info->flags & IEEE80211_TX_STAT_ACK)
+ ifmgd->flags |= IEEE80211_STA_CON_POLL_ACKED;
+
+ /*
+ * FIXME: report negative failure somehow, that way
+ * there's no need to wait for the timer to
+ * trigger
+ */
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
+ }
+
+ }
+ rcu_read_unlock();
+
+ /* trying to go into power save */
+ /* FIXME: add check for IEEE80211_HW_PS_NULLFUNC_STACK */
+ if (local->ps_sdata && ieee80211_has_pm(fc)) {
if (info->flags & IEEE80211_TX_STAT_ACK) {
local->ps_sdata->u.mgd.flags |=
IEEE80211_STA_NULLFUNC_ACKED;