Allow AP mode to disconnect STAs based on low ACK condition
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 disconnect stations when the data connection is not working properly, e.g., due to the STA having went outside the range of the AP. This is disabled by default and can be enabled with disassoc_low_ack=1 in hostapd or wpa_supplicant configuration file. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
d3e01b9d71
commit
0d7e5a3a29
14 changed files with 84 additions and 3 deletions
|
@ -2032,6 +2032,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
|||
else
|
||||
bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
} else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
|
||||
bss->disassoc_low_ack = atoi(pos);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
|
||||
"item '%s'", line, buf);
|
||||
|
|
|
@ -342,6 +342,11 @@ wmm_ac_vo_acm=0
|
|||
# default: 300 (i.e., 5 minutes)
|
||||
#ap_max_inactivity=300
|
||||
|
||||
# Disassociate stations based on excessive transmission failures or other
|
||||
# indications of connection loss. This depends on the driver capabilities and
|
||||
# may not be available with all drivers.
|
||||
#disassoc_low_ack=1
|
||||
|
||||
# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
|
||||
# remain asleep). Default: 65535 (no limit apart from field size)
|
||||
#max_listen_interval=100
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -231,6 +231,22 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
|
|||
}
|
||||
|
||||
|
||||
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (!sta || !hapd->conf->disassoc_low_ack)
|
||||
return;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
|
||||
"missing ACKs");
|
||||
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 +516,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||
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;
|
||||
|
|
|
@ -247,5 +247,6 @@ void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
|
|||
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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -2287,6 +2287,15 @@ enum wpa_event_type {
|
|||
* details of the frame.
|
||||
*/
|
||||
EVENT_UNPROT_DISASSOC,
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
|
||||
|
||||
|
@ -2732,6 +2741,14 @@ union wpa_event_data {
|
|||
const u8 *da;
|
||||
u16 reason_code;
|
||||
} unprot_disassoc;
|
||||
|
||||
/**
|
||||
* struct low_ack - Data for EVENT_STATION_LOW_ACK events
|
||||
* @addr: station address
|
||||
*/
|
||||
struct low_ack {
|
||||
u8 addr[ETH_ALEN];
|
||||
} low_ack;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1210,6 +1210,7 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
|
|||
[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;
|
||||
|
@ -1224,12 +1225,21 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
|
|||
return;
|
||||
}
|
||||
|
||||
os_memset(&ed, 0, sizeof(ed));
|
||||
|
||||
if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
|
||||
if (!tb[NL80211_ATTR_MAC])
|
||||
return;
|
||||
os_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");
|
||||
|
|
|
@ -191,6 +191,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
|
|||
else
|
||||
bss->max_num_sta = wpa_s->conf->max_num_sta;
|
||||
|
||||
bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2408,7 +2408,8 @@ static const struct global_parse_data global_fields[] = {
|
|||
{ 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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -690,6 +690,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
|||
fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
|
||||
if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
|
||||
fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
|
||||
if (config->disassoc_low_ack)
|
||||
fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NO_CONFIG_WRITE */
|
||||
|
|
|
@ -269,6 +269,8 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
|
|||
&config->filter_ssids);
|
||||
wpa_config_read_reg_dword(hk, TEXT("max_num_sta"),
|
||||
(int *) &config->max_num_sta);
|
||||
wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
|
||||
(int *) &config->disassoc_low_ack);
|
||||
|
||||
return errors ? -1 : 0;
|
||||
}
|
||||
|
@ -609,6 +611,8 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
|
|||
config->filter_ssids, 0);
|
||||
wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
|
||||
config->max_num_sta, DEFAULT_MAX_NUM_STA);
|
||||
wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
|
||||
config->disassoc_low_ack, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2030,6 +2030,13 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
|||
wpa_supplicant_event_unprot_disassoc(wpa_s,
|
||||
&data->unprot_disassoc);
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue