diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 0d0183f6e..7fc520c48 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -537,14 +537,24 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, const char *cmd) { u8 addr[ETH_ALEN]; - const char *url; + const char *url, *timerstr; u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; size_t url_len; + int disassoc_timer; if (hwaddr_aton(cmd, addr)) return -1; - url = cmd + 17; + + timerstr = cmd + 17; + if (*timerstr != ' ') + return -1; + timerstr++; + disassoc_timer = atoi(timerstr); + if (disassoc_timer < 0 || disassoc_timer > 65535) + return -1; + + url = os_strchr(timerstr, ' '); if (*url != ' ') return -1; url++; @@ -564,8 +574,9 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, mgmt->u.action.u.bss_tm_req.dialog_token = 1; mgmt->u.action.u.bss_tm_req.req_mode = WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); - mgmt->u.action.u.bss_tm_req.validity_interval = 0; + mgmt->u.action.u.bss_tm_req.disassoc_timer = + host_to_le16(disassoc_timer); + mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; pos = mgmt->u.action.u.bss_tm_req.variable; @@ -580,6 +591,25 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, return -1; } + /* send disassociation frame after time-out */ + if (disassoc_timer) { + struct sta_info *sta; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " + "for ESS disassociation imminent message", + MAC2STR(addr)); + return -1; + } + + sta->timeout_next = STA_DISASSOC_FROM_CLI; + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(disassoc_timer / 1000, + disassoc_timer % 1000 * 1000, + ap_handle_timer, hapd, sta); + } + return 0; } diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index a8a8dfb68..661f709e3 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -588,14 +588,14 @@ static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, char buf[300]; int res; - if (argc < 2) { - printf("Invalid 'ess_disassoc' command - two arguments (STA " - "addr and URL) are needed\n"); + if (argc < 3) { + printf("Invalid 'ess_disassoc' command - three arguments (STA " + "addr, disassoc timer, and URL) are needed\n"); return -1; } - res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s", - argv[0], argv[1]); + res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s", + argv[0], argv[1], argv[2]); if (res < 0 || res >= (int) sizeof(buf)) return -1; return wpa_ctrl_command(ctrl, buf); diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 12ccaaa08..833f1b23a 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -283,6 +283,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) struct hostapd_data *hapd = eloop_ctx; struct sta_info *sta = timeout_ctx; unsigned long next_time = 0; + int reason; wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d", __func__, MAC2STR(sta->addr), sta->flags, @@ -378,9 +379,11 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) hapd, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); } else { - hostapd_drv_sta_disassoc( - hapd, sta->addr, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); + reason = (sta->timeout_next == STA_DISASSOC) ? + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : + WLAN_REASON_PREV_AUTH_NOT_VALID; + + hostapd_drv_sta_disassoc(hapd, sta->addr, reason); } } @@ -394,6 +397,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) hapd, sta); break; case STA_DISASSOC: + case STA_DISASSOC_FROM_CLI: ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~WLAN_STA_ASSOC; ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); @@ -405,14 +409,16 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated due to " "inactivity"); + reason = (sta->timeout_next == STA_DISASSOC) ? + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : + WLAN_REASON_PREV_AUTH_NOT_VALID; sta->timeout_next = STA_DEAUTH; wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)", __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, hapd, sta); - mlme_disassociate_indication( - hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); + mlme_disassociate_indication(hapd, sta, reason); break; case STA_DEAUTH: case STA_REMOVE: diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 32ea46e04..f8f5a8376 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -62,7 +62,8 @@ struct sta_info { u8 previous_ap[6]; enum { - STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE + STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE, + STA_DISASSOC_FROM_CLI } timeout_next; u16 deauth_reason;