[RFC] wpa_s/hostapd/nl80211: disassociate stations with low ACK

Johannes Berg johannes
Mon Nov 29 03:40:47 PST 2010


From: Johannes Berg <johannes.berg at intel.com>

The nl80211 driver can report low ACK condition
(in fact it reports complete loss right now only).
Use that, along with a config option, to disassoc
stations.

Signed-off-by: Johannes Berg <johannes.berg at intel.com>
---
Needs an update to nl80211_copy.h!

 hostapd/config_file.c        |    2 ++
 src/ap/ap_config.h           |    2 ++
 src/ap/drv_callbacks.c       |   19 +++++++++++++++++++
 src/ap/hostapd.h             |    1 +
 src/common/ieee802_11_defs.h |    2 ++
 src/drivers/driver.h         |   19 ++++++++++++++++++-
 src/drivers/driver_nl80211.c |   14 ++++++++++++--
 wpa_supplicant/ap.c          |    2 ++
 wpa_supplicant/config.c      |    3 ++-
 wpa_supplicant/config.h      |    5 +++++
 wpa_supplicant/events.c      |    7 +++++++
 11 files changed, 72 insertions(+), 4 deletions(-)

--- hostap.orig/src/drivers/driver.h	2010-11-29 12:20:53.000000000 +0100
+++ hostap/src/drivers/driver.h	2010-11-29 12:21:23.000000000 +0100
@@ -2266,7 +2266,16 @@ enum wpa_event_type {
 	 * (e.g., based on RSSI or channel use). This information can be used
 	 * to improve channel selection for a new AP/P2P group.
 	 */
-	EVENT_BEST_CHANNEL
+	EVENT_BEST_CHANNEL,
+
+	/**
+	 * EVENT_STATION_LOW_ACK
+	 *
+	 * Driver generates this event whenever it detected that a particular
+	 * station was lost. Detection can be through massive transmission
+	 * failures for example.
+	 */
+	EVENT_STATION_LOW_ACK
 };
 
 
@@ -2700,6 +2709,14 @@ union wpa_event_data {
 		int freq_5;
 		int freq_overall;
 	} best_chan;
+
+	/**
+	 * struct low_ack - Data for EVENT_STATION_LOW_ACK events
+	 * @addr: station address
+	 */
+	struct low_ack {
+		u8 addr[ETH_ALEN];
+	} low_ack;
 };
 
 /**
--- hostap.orig/src/drivers/driver_nl80211.c	2010-11-29 12:20:53.000000000 +0100
+++ hostap/src/drivers/driver_nl80211.c	2010-11-29 12:21:23.000000000 +0100
@@ -1170,6 +1170,7 @@ static void nl80211_cqm_event(struct wpa
 		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
 		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
 		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+		[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
 	};
 	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
 	enum nl80211_cqm_rssi_threshold_event event;
@@ -1184,12 +1185,21 @@ static void nl80211_cqm_event(struct wpa
 		return;
 	}
 
+	os_memset(&ed, 0, sizeof(ed));
+
+	if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+		if (!tb[NL80211_ATTR_MAC])
+			return;
+		memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+		       ETH_ALEN);
+		wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+		return;
+	}
+
 	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
 		return;
 	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
 
-	os_memset(&ed, 0, sizeof(ed));
-
 	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
 		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
 			   "event: RSSI high");
--- hostap.orig/hostapd/config_file.c	2010-11-29 12:20:52.000000000 +0100
+++ hostap/hostapd/config_file.c	2010-11-29 12:21:23.000000000 +0100
@@ -2032,6 +2032,8 @@ struct hostapd_config * hostapd_config_r
 			else
 				bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
 #endif /* CONFIG_P2P_MANAGER */
+		} else if (os_strcmp(buf, "disassoc_low_ack")) {
+			bss->disassoc_low_ack = atoi(pos);
 		} else {
 			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
 				   "item '%s'", line, buf);
--- hostap.orig/src/ap/ap_config.h	2010-11-29 12:20:52.000000000 +0100
+++ hostap/src/ap/ap_config.h	2010-11-29 12:21:23.000000000 +0100
@@ -323,6 +323,8 @@ struct hostapd_bss_config {
 #define P2P_MANAGE BIT(3)
 #define P2P_ALLOW_CROSS_CONNECTION BIT(4)
 	int p2p;
+
+	int disassoc_low_ack;
 };
 
 
--- hostap.orig/src/ap/drv_callbacks.c	2010-11-29 12:20:52.000000000 +0100
+++ hostap/src/ap/drv_callbacks.c	2010-11-29 12:27:35.000000000 +0100
@@ -231,6 +231,20 @@ void hostapd_notif_disassoc(struct hosta
 }
 
 
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+
+	if (!sta)
+		return;
+
+	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
+	if (sta)
+		ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+
+}
+
+
 #ifdef HOSTAPD
 
 #ifdef NEED_AP_MLME
@@ -500,6 +514,11 @@ void wpa_supplicant_event(void *ctx, enu
 		if (data)
 			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
 		break;
+	case EVENT_STATION_LOW_ACK:
+		if (!data)
+			break;
+		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
--- hostap.orig/wpa_supplicant/ap.c	2010-11-29 12:20:53.000000000 +0100
+++ hostap/wpa_supplicant/ap.c	2010-11-29 12:21:23.000000000 +0100
@@ -191,6 +191,8 @@ static int wpa_supplicant_conf_ap(struct
 	else
 		bss->max_num_sta = wpa_s->conf->max_num_sta;
 
+	bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+
 	return 0;
 }
 
--- hostap.orig/wpa_supplicant/config.c	2010-11-29 12:20:53.000000000 +0100
+++ hostap/wpa_supplicant/config.c	2010-11-29 12:21:23.000000000 +0100
@@ -2408,7 +2408,8 @@ static const struct global_parse_data gl
 	{ FUNC(country), CFG_CHANGED_COUNTRY },
 	{ INT(bss_max_count), 0 },
 	{ INT_RANGE(filter_ssids, 0, 1), 0 },
-	{ INT(max_num_sta), 0 }
+	{ INT(max_num_sta), 0 },
+	{ INT_RANGE(disassoc_low_ack, 0, 1), 0 }
 };
 
 #undef FUNC
--- hostap.orig/wpa_supplicant/config.h	2010-11-29 12:20:53.000000000 +0100
+++ hostap/wpa_supplicant/config.h	2010-11-29 12:21:23.000000000 +0100
@@ -400,6 +400,11 @@ struct wpa_config {
 	 * changed_parameters - Bitmap of changed parameters since last update
 	 */
 	unsigned int changed_parameters;
+
+	/**
+	 * disassoc_low_ack - disassocenticate stations with massive packet loss
+	 */
+	int disassoc_low_ack;
 };
 
 
--- hostap.orig/src/common/ieee802_11_defs.h	2010-11-29 12:20:53.000000000 +0100
+++ hostap/src/common/ieee802_11_defs.h	2010-11-29 12:21:23.000000000 +0100
@@ -174,6 +174,8 @@
 #define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
 #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24
+/* IEEE 802.11e */
+#define WLAN_REASON_DISASSOC_LOW_ACK 34
 
 
 /* Information Element IDs */
--- hostap.orig/src/ap/hostapd.h	2010-11-29 12:27:09.000000000 +0100
+++ hostap/src/ap/hostapd.h	2010-11-29 12:27:34.000000000 +0100
@@ -247,5 +247,6 @@ void hostapd_prune_associations(struct h
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 			const u8 *ie, size_t ielen);
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
 
 #endif /* HOSTAPD_H */
--- hostap.orig/wpa_supplicant/events.c	2010-11-29 12:25:02.000000000 +0100
+++ hostap/wpa_supplicant/events.c	2010-11-29 12:28:35.000000000 +0100
@@ -1970,6 +1970,13 @@ void wpa_supplicant_event(void *ctx, enu
 					      data->best_chan.freq_overall);
 #endif /* CONFIG_P2P */
 		break;
+	case EVENT_STATION_LOW_ACK:
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data)
+			hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0],
+						  data->low_ack.addr);
+#endif /* CONFIG_AP */
+		break;
 	default:
 		wpa_printf(MSG_INFO, "Unknown event %d", event);
 		break;





More information about the Hostap mailing list