Search Linux Wireless

[RFC PATCH 2/3] mac80211: use nullfunc in connection monitor

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Kalle Valo <kalle.valo@xxxxxxxxx>

Currently mac80211 is periodically sending probe request to the AP
during idle periods to make sure that the connection to the AP works. But
on hardware which have IEEE80211_HW_REPORTS_TX_ACK_STATUS we can use
nullfunc frames. This is because  we can check from the tx status if an
acknowledgement frame was received from the AP or not.

Major benefit from this is that we don't need to wakeup from power save
just for this and can save power. Another benefit is that we can faster notice
if the AP is lost and hopefully reduce the roaming time in that case.
(NB: these are not implemented yet)

In the first phase we just use nullfunc frames instead of the probe requsts
and do not change the mlme drastically, just to be on the safe side. Later
on the logic can be improved and we can get the benefits mentioned above.

Signed-off-by: Kalle Valo <kalle.valo@xxxxxxxxx>
---
 net/mac80211/ieee80211_i.h |    1 +
 net/mac80211/mlme.c        |   37 ++++++++++++++++++++++++------
 net/mac80211/status.c      |   54 +++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 241533e..79e065b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -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 {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 41812a1..4b9596f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -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);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 8a17454..5311977 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -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;

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux