Use wpa_radio work for connection
This protects against conflicting offchannel operations during connection (authentication, association, EAP exchanges, 4-way handshake). Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
b9e6d7001d
commit
6ac4b15ef8
3 changed files with 184 additions and 16 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* wpa_supplicant - SME
|
* wpa_supplicant - SME
|
||||||
* Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2009-2014, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -157,6 +157,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
if (bss == NULL) {
|
if (bss == NULL) {
|
||||||
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
|
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
|
||||||
"the network");
|
"the network");
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,6 +245,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
&wpa_s->sme.assoc_req_ie_len)) {
|
&wpa_s->sme.assoc_req_ie_len)) {
|
||||||
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
|
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
|
||||||
"key management and encryption suites");
|
"key management and encryption suites");
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
|
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
|
||||||
|
@ -263,6 +265,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
|
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
|
||||||
"key management and encryption suites (no "
|
"key management and encryption suites (no "
|
||||||
"scan results)");
|
"scan results)");
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_WPS
|
#ifdef CONFIG_WPS
|
||||||
|
@ -386,8 +389,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
bss->bssid);
|
bss->bssid);
|
||||||
else
|
else
|
||||||
resp = sme_auth_build_sae_confirm(wpa_s);
|
resp = sme_auth_build_sae_confirm(wpa_s);
|
||||||
if (resp == NULL)
|
if (resp == NULL) {
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
params.sae_data = wpabuf_head(resp);
|
params.sae_data = wpabuf_head(resp);
|
||||||
params.sae_data_len = wpabuf_len(resp);
|
params.sae_data_len = wpabuf_len(resp);
|
||||||
wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
|
wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
|
||||||
|
@ -417,6 +422,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
wpas_connection_failed(wpa_s, bss->bssid);
|
wpas_connection_failed(wpa_s, bss->bssid);
|
||||||
wpa_supplicant_mark_disassoc(wpa_s);
|
wpa_supplicant_mark_disassoc(wpa_s);
|
||||||
wpabuf_free(resp);
|
wpabuf_free(resp);
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,15 +438,56 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
|
||||||
|
{
|
||||||
|
struct wpa_connect_work *cwork = work->ctx;
|
||||||
|
struct wpa_supplicant *wpa_s = work->wpa_s;
|
||||||
|
|
||||||
|
if (deinit) {
|
||||||
|
wpas_connect_work_free(cwork);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_s->connect_work = work;
|
||||||
|
|
||||||
|
if (!wpas_valid_bss_ssid(wpa_s, cwork->bss, cwork->ssid)) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "SME: BSS/SSID entry for authentication not valid anymore - drop connection attempt");
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void sme_authenticate(struct wpa_supplicant *wpa_s,
|
void sme_authenticate(struct wpa_supplicant *wpa_s,
|
||||||
struct wpa_bss *bss, struct wpa_ssid *ssid)
|
struct wpa_bss *bss, struct wpa_ssid *ssid)
|
||||||
{
|
{
|
||||||
|
struct wpa_connect_work *cwork;
|
||||||
|
|
||||||
|
if (bss == NULL || ssid == NULL)
|
||||||
|
return;
|
||||||
|
if (wpa_s->connect_work) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Reject sme_authenticate() call since connect_work exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cwork = os_zalloc(sizeof(*cwork));
|
||||||
|
if (cwork == NULL)
|
||||||
|
return;
|
||||||
|
cwork->bss = bss;
|
||||||
|
cwork->ssid = ssid;
|
||||||
|
cwork->sme = 1;
|
||||||
|
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
wpa_s->sme.sae.state = SAE_NOTHING;
|
wpa_s->sme.sae.state = SAE_NOTHING;
|
||||||
wpa_s->sme.sae.send_confirm = 0;
|
wpa_s->sme.sae.send_confirm = 0;
|
||||||
wpa_s->sme.sae_group_index = 0;
|
wpa_s->sme.sae_group_index = 0;
|
||||||
#endif /* CONFIG_SAE */
|
#endif /* CONFIG_SAE */
|
||||||
sme_send_authentication(wpa_s, bss, ssid, 1);
|
|
||||||
|
if (radio_add_work(wpa_s, bss->freq, "sme-connect", 1,
|
||||||
|
sme_auth_start_cb, cwork) < 0)
|
||||||
|
wpas_connect_work_free(cwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -649,6 +649,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
|
||||||
wpa_supplicant_state_txt(wpa_s->wpa_state),
|
wpa_supplicant_state_txt(wpa_s->wpa_state),
|
||||||
wpa_supplicant_state_txt(state));
|
wpa_supplicant_state_txt(state));
|
||||||
|
|
||||||
|
if (state == WPA_COMPLETED)
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
|
|
||||||
if (state != WPA_SCANNING)
|
if (state != WPA_SCANNING)
|
||||||
wpa_supplicant_notify_scanning(wpa_s, 0);
|
wpa_supplicant_notify_scanning(wpa_s, 0);
|
||||||
|
|
||||||
|
@ -1234,6 +1237,70 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_bss *test_bss)
|
||||||
|
{
|
||||||
|
struct wpa_bss *bss;
|
||||||
|
|
||||||
|
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
||||||
|
if (bss == test_bss)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_ssid *test_ssid)
|
||||||
|
{
|
||||||
|
struct wpa_ssid *ssid;
|
||||||
|
|
||||||
|
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
|
||||||
|
if (ssid == test_ssid)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
|
||||||
|
struct wpa_ssid *test_ssid)
|
||||||
|
{
|
||||||
|
if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_connect_work_free(struct wpa_connect_work *cwork)
|
||||||
|
{
|
||||||
|
if (cwork == NULL)
|
||||||
|
return;
|
||||||
|
os_free(cwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct wpa_connect_work *cwork;
|
||||||
|
struct wpa_radio_work *work = wpa_s->connect_work;
|
||||||
|
|
||||||
|
if (!work)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpa_s->connect_work = NULL;
|
||||||
|
cwork = work->ctx;
|
||||||
|
work->ctx = NULL;
|
||||||
|
wpas_connect_work_free(cwork);
|
||||||
|
radio_work_done(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wpa_supplicant_associate - Request association
|
* wpa_supplicant_associate - Request association
|
||||||
* @wpa_s: Pointer to wpa_supplicant data
|
* @wpa_s: Pointer to wpa_supplicant data
|
||||||
|
@ -1245,19 +1312,7 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
|
||||||
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
||||||
struct wpa_bss *bss, struct wpa_ssid *ssid)
|
struct wpa_bss *bss, struct wpa_ssid *ssid)
|
||||||
{
|
{
|
||||||
u8 wpa_ie[200];
|
struct wpa_connect_work *cwork;
|
||||||
size_t wpa_ie_len;
|
|
||||||
int use_crypt, ret, i, bssid_changed;
|
|
||||||
int algs = WPA_AUTH_ALG_OPEN;
|
|
||||||
unsigned int cipher_pairwise, cipher_group;
|
|
||||||
struct wpa_driver_associate_params params;
|
|
||||||
int wep_keys_set = 0;
|
|
||||||
int assoc_failed = 0;
|
|
||||||
struct wpa_ssid *old_ssid;
|
|
||||||
#ifdef CONFIG_HT_OVERRIDES
|
|
||||||
struct ieee80211_ht_capabilities htcaps;
|
|
||||||
struct ieee80211_ht_capabilities htcaps_mask;
|
|
||||||
#endif /* CONFIG_HT_OVERRIDES */
|
|
||||||
|
|
||||||
#ifdef CONFIG_IBSS_RSN
|
#ifdef CONFIG_IBSS_RSN
|
||||||
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
||||||
|
@ -1298,6 +1353,58 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wpa_s->connect_work) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cwork = os_zalloc(sizeof(*cwork));
|
||||||
|
if (cwork == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cwork->bss = bss;
|
||||||
|
cwork->ssid = ssid;
|
||||||
|
|
||||||
|
if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
|
||||||
|
wpas_start_assoc_cb, cwork) < 0) {
|
||||||
|
os_free(cwork);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
||||||
|
{
|
||||||
|
struct wpa_connect_work *cwork = work->ctx;
|
||||||
|
struct wpa_bss *bss = cwork->bss;
|
||||||
|
struct wpa_ssid *ssid = cwork->ssid;
|
||||||
|
struct wpa_supplicant *wpa_s = work->wpa_s;
|
||||||
|
u8 wpa_ie[200];
|
||||||
|
size_t wpa_ie_len;
|
||||||
|
int use_crypt, ret, i, bssid_changed;
|
||||||
|
int algs = WPA_AUTH_ALG_OPEN;
|
||||||
|
unsigned int cipher_pairwise, cipher_group;
|
||||||
|
struct wpa_driver_associate_params params;
|
||||||
|
int wep_keys_set = 0;
|
||||||
|
int assoc_failed = 0;
|
||||||
|
struct wpa_ssid *old_ssid;
|
||||||
|
#ifdef CONFIG_HT_OVERRIDES
|
||||||
|
struct ieee80211_ht_capabilities htcaps;
|
||||||
|
struct ieee80211_ht_capabilities htcaps_mask;
|
||||||
|
#endif /* CONFIG_HT_OVERRIDES */
|
||||||
|
|
||||||
|
if (deinit) {
|
||||||
|
wpas_connect_work_free(cwork);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_s->connect_work = work;
|
||||||
|
|
||||||
|
if (!wpas_valid_bss_ssid(wpa_s, bss, ssid)) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
os_memset(¶ms, 0, sizeof(params));
|
os_memset(¶ms, 0, sizeof(params));
|
||||||
wpa_s->reassociate = 0;
|
wpa_s->reassociate = 0;
|
||||||
if (bss && !wpas_driver_bss_selection(wpa_s)) {
|
if (bss && !wpas_driver_bss_selection(wpa_s)) {
|
||||||
|
@ -3887,6 +3994,8 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
|
||||||
int count;
|
int count;
|
||||||
int *freqs = NULL;
|
int *freqs = NULL;
|
||||||
|
|
||||||
|
wpas_connect_work_done(wpa_s);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove possible authentication timeout since the connection failed.
|
* Remove possible authentication timeout since the connection failed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -305,6 +305,17 @@ void radio_work_done(struct wpa_radio_work *work);
|
||||||
void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s,
|
void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s,
|
||||||
const char *type);
|
const char *type);
|
||||||
|
|
||||||
|
struct wpa_connect_work {
|
||||||
|
unsigned int sme:1;
|
||||||
|
struct wpa_bss *bss;
|
||||||
|
struct wpa_ssid *ssid;
|
||||||
|
};
|
||||||
|
|
||||||
|
int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
|
||||||
|
struct wpa_ssid *test_ssid);
|
||||||
|
void wpas_connect_work_free(struct wpa_connect_work *cwork);
|
||||||
|
void wpas_connect_work_done(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* offchannel_send_action_result - Result of offchannel send Action frame
|
* offchannel_send_action_result - Result of offchannel send Action frame
|
||||||
*/
|
*/
|
||||||
|
@ -775,6 +786,7 @@ struct wpa_supplicant {
|
||||||
#endif /* CONFIG_TESTING_GET_GTK */
|
#endif /* CONFIG_TESTING_GET_GTK */
|
||||||
|
|
||||||
unsigned int num_multichan_concurrent;
|
unsigned int num_multichan_concurrent;
|
||||||
|
struct wpa_radio_work *connect_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue