aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2014-01-03 14:50:32 (GMT)
committerJouni Malinen <j@w1.fi>2014-01-07 08:45:09 (GMT)
commit6ac4b15ef8af434d216fd2dac62ec82948ab0fbd (patch)
tree51a67b8ebd8505d8b67481d0ffb93907386b25d3 /wpa_supplicant
parentb9e6d7001d5408b3dd9c9e74df3f75732823d216 (diff)
downloadhostap-6ac4b15ef8af434d216fd2dac62ec82948ab0fbd.zip
hostap-6ac4b15ef8af434d216fd2dac62ec82948ab0fbd.tar.gz
hostap-6ac4b15ef8af434d216fd2dac62ec82948ab0fbd.tar.bz2
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>
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/sme.c53
-rw-r--r--wpa_supplicant/wpa_supplicant.c135
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h12
3 files changed, 184 insertions, 16 deletions
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index d7b7be8..43f40cd 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1,6 +1,6 @@
/*
* 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.
* See README for more details.
@@ -157,6 +157,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
"the network");
+ wpas_connect_work_done(wpa_s);
return;
}
@@ -244,6 +245,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
&wpa_s->sme.assoc_req_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites");
+ wpas_connect_work_done(wpa_s);
return;
}
} 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 "
"key management and encryption suites (no "
"scan results)");
+ wpas_connect_work_done(wpa_s);
return;
}
#ifdef CONFIG_WPS
@@ -386,8 +389,10 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
bss->bssid);
else
resp = sme_auth_build_sae_confirm(wpa_s);
- if (resp == NULL)
+ if (resp == NULL) {
+ wpas_connect_work_done(wpa_s);
return;
+ }
params.sae_data = wpabuf_head(resp);
params.sae_data_len = wpabuf_len(resp);
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);
wpa_supplicant_mark_disassoc(wpa_s);
wpabuf_free(resp);
+ wpas_connect_work_done(wpa_s);
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,
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
wpa_s->sme.sae.state = SAE_NOTHING;
wpa_s->sme.sae.send_confirm = 0;
wpa_s->sme.sae_group_index = 0;
#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);
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 138e975..2480e56 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -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(state));
+ if (state == WPA_COMPLETED)
+ wpas_connect_work_done(wpa_s);
+
if (state != WPA_SCANNING)
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_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,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
- 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 */
+ struct wpa_connect_work *cwork;
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1298,6 +1353,58 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
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(&params, 0, sizeof(params));
wpa_s->reassociate = 0;
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 *freqs = NULL;
+ wpas_connect_work_done(wpa_s);
+
/*
* Remove possible authentication timeout since the connection failed.
*/
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 9558495..b8f41c8 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -305,6 +305,17 @@ void radio_work_done(struct wpa_radio_work *work);
void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s,
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
*/
@@ -775,6 +786,7 @@ struct wpa_supplicant {
#endif /* CONFIG_TESTING_GET_GTK */
unsigned int num_multichan_concurrent;
+ struct wpa_radio_work *connect_work;
};