AP: Add support for full station state
Add support for drivers that support full AP client state, i.e., can handle adding stations that are not associated yet. For such drivers, add a station after processing the authentication request, instead of adding it in the association response callback. Doing so is beneficial in cases where the driver cannot handle the add station request, in which case it is useless to perform the complete connection establishment. Signed-off-by: Ayala Beker <ayala.beker@intel.com>
This commit is contained in:
parent
dc55b6b672
commit
bb598c3bdd
5 changed files with 209 additions and 73 deletions
|
@ -33,6 +33,10 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
|
||||||
res |= WPA_STA_SHORT_PREAMBLE;
|
res |= WPA_STA_SHORT_PREAMBLE;
|
||||||
if (flags & WLAN_STA_MFP)
|
if (flags & WLAN_STA_MFP)
|
||||||
res |= WPA_STA_MFP;
|
res |= WPA_STA_MFP;
|
||||||
|
if (flags & WLAN_STA_AUTH)
|
||||||
|
res |= WPA_STA_AUTHENTICATED;
|
||||||
|
if (flags & WLAN_STA_ASSOC)
|
||||||
|
res |= WPA_STA_ASSOCIATED;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +394,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||||
u16 listen_interval,
|
u16 listen_interval,
|
||||||
const struct ieee80211_ht_capabilities *ht_capab,
|
const struct ieee80211_ht_capabilities *ht_capab,
|
||||||
const struct ieee80211_vht_capabilities *vht_capab,
|
const struct ieee80211_vht_capabilities *vht_capab,
|
||||||
u32 flags, u8 qosinfo, u8 vht_opmode)
|
u32 flags, u8 qosinfo, u8 vht_opmode, int set)
|
||||||
{
|
{
|
||||||
struct hostapd_sta_add_params params;
|
struct hostapd_sta_add_params params;
|
||||||
|
|
||||||
|
@ -412,6 +416,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||||
params.vht_opmode = vht_opmode;
|
params.vht_opmode = vht_opmode;
|
||||||
params.flags = hostapd_sta_flags_to_drv(flags);
|
params.flags = hostapd_sta_flags_to_drv(flags);
|
||||||
params.qosinfo = qosinfo;
|
params.qosinfo = qosinfo;
|
||||||
|
params.set = set;
|
||||||
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
|
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||||
u16 listen_interval,
|
u16 listen_interval,
|
||||||
const struct ieee80211_ht_capabilities *ht_capab,
|
const struct ieee80211_ht_capabilities *ht_capab,
|
||||||
const struct ieee80211_vht_capabilities *vht_capab,
|
const struct ieee80211_vht_capabilities *vht_capab,
|
||||||
u32 flags, u8 qosinfo, u8 vht_opmode);
|
u32 flags, u8 qosinfo, u8 vht_opmode, int set);
|
||||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||||
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
||||||
size_t elem_len);
|
size_t elem_len);
|
||||||
|
|
|
@ -251,19 +251,20 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
#endif /* CONFIG_NO_RC4 */
|
#endif /* CONFIG_NO_RC4 */
|
||||||
|
|
||||||
|
|
||||||
static void send_auth_reply(struct hostapd_data *hapd,
|
static int send_auth_reply(struct hostapd_data *hapd,
|
||||||
const u8 *dst, const u8 *bssid,
|
const u8 *dst, const u8 *bssid,
|
||||||
u16 auth_alg, u16 auth_transaction, u16 resp,
|
u16 auth_alg, u16 auth_transaction, u16 resp,
|
||||||
const u8 *ies, size_t ies_len)
|
const u8 *ies, size_t ies_len)
|
||||||
{
|
{
|
||||||
struct ieee80211_mgmt *reply;
|
struct ieee80211_mgmt *reply;
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
size_t rlen;
|
size_t rlen;
|
||||||
|
int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
|
||||||
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
|
rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
|
||||||
buf = os_zalloc(rlen);
|
buf = os_zalloc(rlen);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
reply = (struct ieee80211_mgmt *) buf;
|
reply = (struct ieee80211_mgmt *) buf;
|
||||||
reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
|
||||||
|
@ -284,9 +285,13 @@ static void send_auth_reply(struct hostapd_data *hapd,
|
||||||
MAC2STR(dst), auth_alg, auth_transaction,
|
MAC2STR(dst), auth_alg, auth_transaction,
|
||||||
resp, (unsigned long) ies_len);
|
resp, (unsigned long) ies_len);
|
||||||
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
|
if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
|
||||||
wpa_printf(MSG_INFO, "send_auth_reply: send");
|
wpa_printf(MSG_INFO, "send_auth_reply: send failed");
|
||||||
|
else
|
||||||
|
reply_res = WLAN_STATUS_SUCCESS;
|
||||||
|
|
||||||
os_free(buf);
|
os_free(buf);
|
||||||
|
|
||||||
|
return reply_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -297,17 +302,25 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
|
||||||
{
|
{
|
||||||
struct hostapd_data *hapd = ctx;
|
struct hostapd_data *hapd = ctx;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
|
int reply_res;
|
||||||
|
|
||||||
send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
|
reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT,
|
||||||
status, ies, ies_len);
|
auth_transaction, status, ies, ies_len);
|
||||||
|
|
||||||
if (status != WLAN_STATUS_SUCCESS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sta = ap_get_sta(hapd, dst);
|
sta = ap_get_sta(hapd, dst);
|
||||||
if (sta == NULL)
|
if (sta == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS ||
|
||||||
|
status != WLAN_STATUS_SUCCESS)) {
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != WLAN_STATUS_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
|
||||||
HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
|
HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
|
||||||
sta->flags |= WLAN_STA_AUTH;
|
sta->flags |= WLAN_STA_AUTH;
|
||||||
|
@ -370,18 +383,19 @@ static int auth_sae_send_commit(struct hostapd_data *hapd,
|
||||||
const u8 *bssid, int update)
|
const u8 *bssid, int update)
|
||||||
{
|
{
|
||||||
struct wpabuf *data;
|
struct wpabuf *data;
|
||||||
|
int reply_res;
|
||||||
|
|
||||||
data = auth_build_sae_commit(hapd, sta, update);
|
data = auth_build_sae_commit(hapd, sta, update);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
|
||||||
send_auth_reply(hapd, sta->addr, bssid,
|
reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
|
||||||
WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
|
WLAN_STATUS_SUCCESS, wpabuf_head(data),
|
||||||
wpabuf_head(data), wpabuf_len(data));
|
wpabuf_len(data));
|
||||||
|
|
||||||
wpabuf_free(data);
|
wpabuf_free(data);
|
||||||
|
|
||||||
return WLAN_STATUS_SUCCESS;
|
return reply_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -390,18 +404,19 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
|
||||||
const u8 *bssid)
|
const u8 *bssid)
|
||||||
{
|
{
|
||||||
struct wpabuf *data;
|
struct wpabuf *data;
|
||||||
|
int reply_res;
|
||||||
|
|
||||||
data = auth_build_sae_confirm(hapd, sta);
|
data = auth_build_sae_confirm(hapd, sta);
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
|
||||||
send_auth_reply(hapd, sta->addr, bssid,
|
reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2,
|
||||||
WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS,
|
WLAN_STATUS_SUCCESS, wpabuf_head(data),
|
||||||
wpabuf_head(data), wpabuf_len(data));
|
wpabuf_len(data));
|
||||||
|
|
||||||
wpabuf_free(data);
|
wpabuf_free(data);
|
||||||
|
|
||||||
return WLAN_STATUS_SUCCESS;
|
return reply_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -699,15 +714,20 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
const struct ieee80211_mgmt *mgmt, size_t len,
|
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||||
u16 auth_transaction, u16 status_code)
|
u16 auth_transaction, u16 status_code)
|
||||||
{
|
{
|
||||||
u16 resp = WLAN_STATUS_SUCCESS;
|
int resp = WLAN_STATUS_SUCCESS;
|
||||||
struct wpabuf *data = NULL;
|
struct wpabuf *data = NULL;
|
||||||
|
|
||||||
if (!sta->sae) {
|
if (!sta->sae) {
|
||||||
if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
|
if (auth_transaction != 1 ||
|
||||||
return;
|
status_code != WLAN_STATUS_SUCCESS) {
|
||||||
|
resp = -1;
|
||||||
|
goto remove_sta;
|
||||||
|
}
|
||||||
sta->sae = os_zalloc(sizeof(*sta->sae));
|
sta->sae = os_zalloc(sizeof(*sta->sae));
|
||||||
if (sta->sae == NULL)
|
if (!sta->sae) {
|
||||||
return;
|
resp = -1;
|
||||||
|
goto remove_sta;
|
||||||
|
}
|
||||||
sta->sae->state = SAE_NOTHING;
|
sta->sae->state = SAE_NOTHING;
|
||||||
sta->sae->sync = 0;
|
sta->sae->sync = 0;
|
||||||
}
|
}
|
||||||
|
@ -747,7 +767,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
if (sta->sae->tmp->anti_clogging_token == NULL) {
|
if (sta->sae->tmp->anti_clogging_token == NULL) {
|
||||||
wpa_printf(MSG_ERROR,
|
wpa_printf(MSG_ERROR,
|
||||||
"SAE: Failed to alloc for anti-clogging token");
|
"SAE: Failed to alloc for anti-clogging token");
|
||||||
return;
|
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
goto remove_sta;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -757,10 +778,11 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
* Authentication frame, and the commit-scalar and
|
* Authentication frame, and the commit-scalar and
|
||||||
* COMMIT-ELEMENT previously sent.
|
* COMMIT-ELEMENT previously sent.
|
||||||
*/
|
*/
|
||||||
if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
|
resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
|
||||||
|
if (resp != WLAN_STATUS_SUCCESS) {
|
||||||
wpa_printf(MSG_ERROR,
|
wpa_printf(MSG_ERROR,
|
||||||
"SAE: Failed to send commit message");
|
"SAE: Failed to send commit message");
|
||||||
return;
|
goto remove_sta;
|
||||||
}
|
}
|
||||||
sta->sae->state = SAE_COMMITTED;
|
sta->sae->state = SAE_COMMITTED;
|
||||||
sta->sae->sync = 0;
|
sta->sae->sync = 0;
|
||||||
|
@ -769,7 +791,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status_code != WLAN_STATUS_SUCCESS)
|
if (status_code != WLAN_STATUS_SUCCESS)
|
||||||
return;
|
goto remove_sta;
|
||||||
|
|
||||||
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
|
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
|
||||||
((const u8 *) mgmt) + len -
|
((const u8 *) mgmt) + len -
|
||||||
|
@ -779,14 +801,15 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"SAE: Drop commit message from " MACSTR " due to reflection attack",
|
"SAE: Drop commit message from " MACSTR " due to reflection attack",
|
||||||
MAC2STR(sta->addr));
|
MAC2STR(sta->addr));
|
||||||
return;
|
goto remove_sta;
|
||||||
}
|
}
|
||||||
if (token && check_sae_token(hapd, sta->addr, token, token_len)
|
if (token && check_sae_token(hapd, sta->addr, token, token_len)
|
||||||
< 0) {
|
< 0) {
|
||||||
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
|
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
|
||||||
"incorrect token from " MACSTR,
|
"incorrect token from " MACSTR,
|
||||||
MAC2STR(sta->addr));
|
MAC2STR(sta->addr));
|
||||||
return;
|
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
goto remove_sta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp != WLAN_STATUS_SUCCESS)
|
if (resp != WLAN_STATUS_SUCCESS)
|
||||||
|
@ -811,7 +834,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
"SAE authentication (RX confirm, status=%u)",
|
"SAE authentication (RX confirm, status=%u)",
|
||||||
status_code);
|
status_code);
|
||||||
if (status_code != WLAN_STATUS_SUCCESS)
|
if (status_code != WLAN_STATUS_SUCCESS)
|
||||||
return;
|
goto remove_sta;
|
||||||
if (sta->sae->state >= SAE_CONFIRMED ||
|
if (sta->sae->state >= SAE_CONFIRMED ||
|
||||||
!(hapd->conf->mesh & MESH_ENABLED)) {
|
!(hapd->conf->mesh & MESH_ENABLED)) {
|
||||||
if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
|
if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
|
||||||
|
@ -828,7 +851,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
"unexpected SAE authentication transaction %u (status=%u)",
|
"unexpected SAE authentication transaction %u (status=%u)",
|
||||||
auth_transaction, status_code);
|
auth_transaction, status_code);
|
||||||
if (status_code != WLAN_STATUS_SUCCESS)
|
if (status_code != WLAN_STATUS_SUCCESS)
|
||||||
return;
|
goto remove_sta;
|
||||||
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
|
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,6 +862,13 @@ reply:
|
||||||
data ? wpabuf_head(data) : (u8 *) "",
|
data ? wpabuf_head(data) : (u8 *) "",
|
||||||
data ? wpabuf_len(data) : 0);
|
data ? wpabuf_len(data) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove_sta:
|
||||||
|
if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
|
||||||
|
status_code != WLAN_STATUS_SUCCESS)) {
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
}
|
||||||
wpabuf_free(data);
|
wpabuf_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,7 +913,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
u16 auth_alg, auth_transaction, status_code;
|
u16 auth_alg, auth_transaction, status_code;
|
||||||
u16 resp = WLAN_STATUS_SUCCESS;
|
u16 resp = WLAN_STATUS_SUCCESS;
|
||||||
struct sta_info *sta = NULL;
|
struct sta_info *sta = NULL;
|
||||||
int res;
|
int res, reply_res;
|
||||||
u16 fc;
|
u16 fc;
|
||||||
const u8 *challenge = NULL;
|
const u8 *challenge = NULL;
|
||||||
u32 session_timeout, acct_interim_interval;
|
u32 session_timeout, acct_interim_interval;
|
||||||
|
@ -1148,6 +1178,46 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
else
|
else
|
||||||
ap_sta_no_session_timeout(hapd, sta);
|
ap_sta_no_session_timeout(hapd, sta);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the driver supports full AP client state, add a station to the
|
||||||
|
* driver before sending authentication reply to make sure the driver
|
||||||
|
* has resources, and not to go through the entire authentication and
|
||||||
|
* association handshake, and fail it at the end.
|
||||||
|
*
|
||||||
|
* If this is not the first transaction, in a multi-step authentication
|
||||||
|
* algorithm, the station already exists in the driver
|
||||||
|
* (sta->added_unassoc = 1) so skip it.
|
||||||
|
*
|
||||||
|
* In mesh mode, the station was already added to the driver when the
|
||||||
|
* NEW_PEER_CANDIDATE event is received.
|
||||||
|
*/
|
||||||
|
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
|
||||||
|
!(hapd->conf->mesh & MESH_ENABLED) &&
|
||||||
|
!(sta->added_unassoc)) {
|
||||||
|
/*
|
||||||
|
* If a station that is already associated to the AP, is trying
|
||||||
|
* to authenticate again, remove the STA entry, in order to make
|
||||||
|
* sure the STA PS state gets cleared and configuration gets
|
||||||
|
* updated. To handle this, station's added_unassoc flag is
|
||||||
|
* cleared once the station has completed association.
|
||||||
|
*/
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
|
||||||
|
WLAN_STA_AUTHORIZED);
|
||||||
|
|
||||||
|
if (hostapd_sta_add(hapd, sta->addr, 0, 0, 0, 0, 0,
|
||||||
|
NULL, NULL, sta->flags, 0, 0, 0)) {
|
||||||
|
hostapd_logger(hapd, sta->addr,
|
||||||
|
HOSTAPD_MODULE_IEEE80211,
|
||||||
|
HOSTAPD_LEVEL_NOTICE,
|
||||||
|
"Could not add STA to kernel driver");
|
||||||
|
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
sta->added_unassoc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (auth_alg) {
|
switch (auth_alg) {
|
||||||
case WLAN_AUTH_OPEN:
|
case WLAN_AUTH_OPEN:
|
||||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
|
@ -1221,8 +1291,15 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
os_free(radius_cui);
|
os_free(radius_cui);
|
||||||
hostapd_free_psk_list(psk);
|
hostapd_free_psk_list(psk);
|
||||||
|
|
||||||
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
|
reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
|
||||||
auth_transaction + 1, resp, resp_ies, resp_ies_len);
|
auth_transaction + 1, resp, resp_ies,
|
||||||
|
resp_ies_len);
|
||||||
|
|
||||||
|
if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
|
||||||
|
reply_res != WLAN_STATUS_SUCCESS)) {
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1662,9 +1739,9 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
u16 status_code, int reassoc, const u8 *ies,
|
u16 status_code, int reassoc, const u8 *ies,
|
||||||
size_t ies_len)
|
size_t ies_len)
|
||||||
{
|
{
|
||||||
int send_len;
|
int send_len;
|
||||||
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
||||||
|
@ -1784,9 +1861,13 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
|
|
||||||
send_len += p - reply->u.assoc_resp.variable;
|
send_len += p - reply->u.assoc_resp.variable;
|
||||||
|
|
||||||
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
|
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
|
||||||
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
|
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WLAN_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1795,7 +1876,7 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||||
int reassoc)
|
int reassoc)
|
||||||
{
|
{
|
||||||
u16 capab_info, listen_interval, seq_ctrl, fc;
|
u16 capab_info, listen_interval, seq_ctrl, fc;
|
||||||
u16 resp = WLAN_STATUS_SUCCESS;
|
u16 resp = WLAN_STATUS_SUCCESS, reply_res;
|
||||||
const u8 *pos;
|
const u8 *pos;
|
||||||
int left, i;
|
int left, i;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
|
@ -1862,6 +1943,12 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||||
wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
|
wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
|
||||||
"prior to authentication since it is using "
|
"prior to authentication since it is using "
|
||||||
"over-the-DS FT", MAC2STR(mgmt->sa));
|
"over-the-DS FT", MAC2STR(mgmt->sa));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark station as authenticated, to avoid adding station
|
||||||
|
* entry in the driver as associated and not authenticated
|
||||||
|
*/
|
||||||
|
sta->flags |= WLAN_STA_AUTH;
|
||||||
} else
|
} else
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
|
if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
|
||||||
|
@ -1989,7 +2076,12 @@ static void handle_assoc(struct hostapd_data *hapd,
|
||||||
sta->timeout_next = STA_NULLFUNC;
|
sta->timeout_next = STA_NULLFUNC;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
|
reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
|
||||||
|
if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS ||
|
||||||
|
reply_res != WLAN_STATUS_SUCCESS)) {
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2031,6 +2123,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
|
||||||
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
||||||
ap_sta_ip6addr_del(hapd, sta);
|
ap_sta_ip6addr_del(hapd, sta);
|
||||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
|
||||||
if (sta->timeout_next == STA_NULLFUNC ||
|
if (sta->timeout_next == STA_NULLFUNC ||
|
||||||
sta->timeout_next == STA_DISASSOC) {
|
sta->timeout_next == STA_DISASSOC) {
|
||||||
|
@ -2407,16 +2500,10 @@ static void handle_auth_cb(struct hostapd_data *hapd,
|
||||||
u16 auth_alg, auth_transaction, status_code;
|
u16 auth_alg, auth_transaction, status_code;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
|
|
||||||
if (!ok) {
|
sta = ap_get_sta(hapd, mgmt->da);
|
||||||
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
|
if (!sta) {
|
||||||
HOSTAPD_LEVEL_NOTICE,
|
wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
|
||||||
"did not acknowledge authentication response");
|
MAC2STR(mgmt->da));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
|
|
||||||
wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
|
|
||||||
(unsigned long) len);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2424,11 +2511,17 @@ static void handle_auth_cb(struct hostapd_data *hapd,
|
||||||
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
|
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
|
||||||
status_code = le_to_host16(mgmt->u.auth.status_code);
|
status_code = le_to_host16(mgmt->u.auth.status_code);
|
||||||
|
|
||||||
sta = ap_get_sta(hapd, mgmt->da);
|
if (!ok) {
|
||||||
if (!sta) {
|
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
|
||||||
wpa_printf(MSG_INFO, "handle_auth_cb: STA " MACSTR " not found",
|
HOSTAPD_LEVEL_NOTICE,
|
||||||
MAC2STR(mgmt->da));
|
"did not acknowledge authentication response");
|
||||||
return;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
|
||||||
|
wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
|
||||||
|
(unsigned long) len);
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status_code == WLAN_STATUS_SUCCESS &&
|
if (status_code == WLAN_STATUS_SUCCESS &&
|
||||||
|
@ -2437,6 +2530,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
|
||||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
HOSTAPD_LEVEL_INFO, "authenticated");
|
HOSTAPD_LEVEL_INFO, "authenticated");
|
||||||
sta->flags |= WLAN_STA_AUTH;
|
sta->flags |= WLAN_STA_AUTH;
|
||||||
|
if (sta->added_unassoc)
|
||||||
|
hostapd_set_sta_flags(hapd, sta);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2475,13 +2577,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
struct ieee80211_ht_capabilities ht_cap;
|
struct ieee80211_ht_capabilities ht_cap;
|
||||||
struct ieee80211_vht_capabilities vht_cap;
|
struct ieee80211_vht_capabilities vht_cap;
|
||||||
|
|
||||||
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
|
|
||||||
sizeof(mgmt->u.assoc_resp))) {
|
|
||||||
wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
|
|
||||||
reassoc, (unsigned long) len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sta = ap_get_sta(hapd, mgmt->da);
|
sta = ap_get_sta(hapd, mgmt->da);
|
||||||
if (!sta) {
|
if (!sta) {
|
||||||
wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
|
wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found",
|
||||||
|
@ -2489,12 +2584,20 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
|
||||||
|
sizeof(mgmt->u.assoc_resp))) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)",
|
||||||
|
reassoc, (unsigned long) len);
|
||||||
|
goto remove_sta;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
|
||||||
HOSTAPD_LEVEL_DEBUG,
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
"did not acknowledge association response");
|
"did not acknowledge association response");
|
||||||
sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
|
sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
|
||||||
return;
|
goto remove_sta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reassoc)
|
if (reassoc)
|
||||||
|
@ -2540,8 +2643,14 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
* Remove the STA entry in order to make sure the STA PS state gets
|
* Remove the STA entry in order to make sure the STA PS state gets
|
||||||
* cleared and configuration gets updated in case of reassociation back
|
* cleared and configuration gets updated in case of reassociation back
|
||||||
* to the same AP.
|
* to the same AP.
|
||||||
|
*
|
||||||
|
* This is relevant for cases, such as FT over the DS, where a station
|
||||||
|
* reassociates back to the same AP but skips the authentication flow
|
||||||
|
* and if working with a driver that doesn't support full AP client
|
||||||
|
* state.
|
||||||
*/
|
*/
|
||||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
if (!sta->added_unassoc)
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211N
|
#ifdef CONFIG_IEEE80211N
|
||||||
if (sta->flags & WLAN_STA_HT)
|
if (sta->flags & WLAN_STA_HT)
|
||||||
|
@ -2557,17 +2666,27 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
sta->listen_interval,
|
sta->listen_interval,
|
||||||
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
|
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
|
||||||
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
|
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
|
||||||
sta->flags, sta->qosinfo, sta->vht_opmode)) {
|
sta->flags, sta->qosinfo, sta->vht_opmode,
|
||||||
|
sta->added_unassoc)) {
|
||||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||||
HOSTAPD_LEVEL_NOTICE,
|
HOSTAPD_LEVEL_NOTICE,
|
||||||
"Could not add STA to kernel driver");
|
"Could not %s STA to kernel driver",
|
||||||
|
sta->added_unassoc ? "set" : "add");
|
||||||
ap_sta_disconnect(hapd, sta, sta->addr,
|
ap_sta_disconnect(hapd, sta, sta->addr,
|
||||||
WLAN_REASON_DISASSOC_AP_BUSY);
|
WLAN_REASON_DISASSOC_AP_BUSY);
|
||||||
|
if (sta->added_unassoc)
|
||||||
|
goto remove_sta;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* added_unassoc flag is set for a station that was added to the driver
|
||||||
|
* in unassociated state. Clear this flag once the station has completed
|
||||||
|
* association, to make sure the STA entry will be cleared from the
|
||||||
|
* driver in case of reassociation back to the same AP.
|
||||||
|
*/
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
|
||||||
if (sta->flags & WLAN_STA_WDS) {
|
if (sta->flags & WLAN_STA_WDS) {
|
||||||
int ret;
|
int ret;
|
||||||
char ifname_wds[IFNAMSIZ + 1];
|
char ifname_wds[IFNAMSIZ + 1];
|
||||||
|
@ -2601,6 +2720,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
|
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
|
||||||
|
|
||||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||||
|
|
||||||
|
remove_sta:
|
||||||
|
if (sta->added_unassoc) {
|
||||||
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -170,8 +170,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
ap_sta_ip6addr_del(hapd, sta);
|
ap_sta_ip6addr_del(hapd, sta);
|
||||||
|
|
||||||
if (!hapd->iface->driver_ap_teardown &&
|
if (!hapd->iface->driver_ap_teardown &&
|
||||||
!(sta->flags & WLAN_STA_PREAUTH))
|
!(sta->flags & WLAN_STA_PREAUTH)) {
|
||||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ap_sta_hash_del(hapd, sta);
|
ap_sta_hash_del(hapd, sta);
|
||||||
ap_sta_list_del(hapd, sta);
|
ap_sta_list_del(hapd, sta);
|
||||||
|
@ -275,8 +277,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
* VLAN.
|
* VLAN.
|
||||||
*/
|
*/
|
||||||
if (hapd->iface->driver_ap_teardown &&
|
if (hapd->iface->driver_ap_teardown &&
|
||||||
!(sta->flags & WLAN_STA_PREAUTH))
|
!(sta->flags & WLAN_STA_PREAUTH)) {
|
||||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||||
|
sta->added_unassoc = 0;
|
||||||
|
}
|
||||||
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NO_VLAN */
|
#endif /* CONFIG_NO_VLAN */
|
||||||
|
@ -673,6 +677,7 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
|
||||||
hapd->conf->iface, MAC2STR(sta->addr));
|
hapd->conf->iface, MAC2STR(sta->addr));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
sta->added_unassoc = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ struct sta_info {
|
||||||
unsigned int session_timeout_set:1;
|
unsigned int session_timeout_set:1;
|
||||||
unsigned int radius_das_match:1;
|
unsigned int radius_das_match:1;
|
||||||
unsigned int ecsa_supported:1;
|
unsigned int ecsa_supported:1;
|
||||||
|
unsigned int added_unassoc:1;
|
||||||
|
|
||||||
u16 auth_alg;
|
u16 auth_alg;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue