aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@codeaurora.org>2019-09-15 13:19:45 (GMT)
committerJouni Malinen <j@w1.fi>2019-09-16 14:25:34 (GMT)
commit16ef233bf1b0c9d3cc4d844622e7df6701edbe72 (patch)
treec135a781d5bb8cf850d598edc339a61968926b85
parentb10e01a795323fbe680475483c5c75b1fc3ceb68 (diff)
downloadhostap-16ef233bf1b0c9d3cc4d844622e7df6701edbe72.zip
hostap-16ef233bf1b0c9d3cc4d844622e7df6701edbe72.tar.gz
hostap-16ef233bf1b0c9d3cc4d844622e7df6701edbe72.tar.bz2
DPP2: Connection status result (Enrollee)
Add support for reporting connection status after provisioning if the Configurator requests this. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
-rw-r--r--src/common/dpp.c92
-rw-r--r--src/common/dpp.h5
-rw-r--r--wpa_supplicant/dpp_supplicant.c165
-rw-r--r--wpa_supplicant/dpp_supplicant.h6
-rw-r--r--wpa_supplicant/events.c22
-rw-r--r--wpa_supplicant/wpa_supplicant.c5
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h6
7 files changed, 298 insertions, 3 deletions
diff --git a/src/common/dpp.c b/src/common/dpp.c
index ca84bea..d35c82e 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -6015,6 +6015,16 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
goto fail;
+#ifdef CONFIG_DPP2
+ status = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_SEND_CONN_STATUS, &status_len);
+ if (status) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested connection status result");
+ auth->conn_status_requested = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
ret = 0;
fail:
@@ -6291,6 +6301,88 @@ fail:
return ret;
}
+
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list)
+{
+ struct wpabuf *msg, *clear, *json;
+ size_t nonce_len, clear_len, attr_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 *wrapped;
+
+ json = wpabuf_alloc(1000);
+ if (!json)
+ return NULL;
+ wpabuf_printf(json, "{\"result\":%d", result);
+ if (ssid) {
+ char ssid_str[6 * SSID_MAX_LEN + 1];
+
+ wpabuf_put_str(json, ",\"ssid\":\"");
+ json_escape_string(ssid_str, sizeof(ssid_str),
+ (const char *) ssid, ssid_len);
+ wpabuf_put_str(json, ssid_str);
+ wpabuf_put_str(json, "\"");
+ }
+ if (channel_list)
+ wpabuf_printf(json, ",\"channelList\":\"%s\"", channel_list);
+ wpabuf_put_str(json, "}");
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
+ wpabuf_head(json), wpabuf_len(json));
+
+ nonce_len = auth->curve->nonce_len;
+ clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
+ attr_len = 4 + clear_len + AES_BLOCK_SIZE;
+ clear = wpabuf_alloc(clear_len);
+ msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
+ if (!clear || !msg)
+ goto fail;
+
+ /* E-nonce */
+ wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
+ wpabuf_put_le16(clear, nonce_len);
+ wpabuf_put_data(clear, auth->e_nonce, nonce_len);
+
+ /* DPP Connection Status */
+ wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
+ wpabuf_put_le16(clear, wpabuf_len(json));
+ wpabuf_put_buf(clear, json);
+
+ /* OUI, OUI type, Crypto Suite, DPP frame type */
+ addr[0] = wpabuf_head_u8(msg) + 2;
+ len[0] = 3 + 1 + 1 + 1;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
+
+ /* Attributes before Wrapped Data (none) */
+ addr[1] = wpabuf_put(msg, 0);
+ len[1] = 0;
+ wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+ wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
+ if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
+ wpabuf_head(clear), wpabuf_len(clear),
+ 2, addr, len, wrapped) < 0)
+ goto fail;
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
+ msg);
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ return msg;
+fail:
+ wpabuf_free(json);
+ wpabuf_free(clear);
+ wpabuf_free(msg);
+ return NULL;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index fa3fd76..d560f4b 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -244,6 +244,7 @@ struct dpp_authentication {
os_time_t net_access_key_expiry;
struct wpabuf *c_sign_key;
int send_conn_status;
+ int conn_status_requested;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -451,6 +452,10 @@ enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
size_t attr_len,
u8 *ssid, size_t *ssid_len,
char **channel_list);
+struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
+ enum dpp_status_error result,
+ const u8 *ssid, size_t ssid_len,
+ const char *channel_list);
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len);
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index b9f4670..020a6d0 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -148,6 +148,8 @@ static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
+ wpa_s->suitable_network = 0;
+ wpa_s->no_suitable_network = 0;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
@@ -157,6 +159,141 @@ static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error result;
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Connection timeout - report Connection Status Result");
+ if (wpa_s->suitable_network)
+ result = DPP_STATUS_AUTH_FAILURE;
+ else if (wpa_s->no_suitable_network)
+ result = DPP_STATUS_NO_AP;
+ else
+ result = 255; /* What to report here for unexpected state? */
+ wpas_dpp_send_conn_status_result(wpa_s, result);
+}
+
+
+static char * wpas_dpp_scan_channel_list(struct wpa_supplicant *wpa_s)
+{
+ char *str, *end, *pos;
+ size_t len;
+ unsigned int i;
+ u8 last_op_class = 0;
+ int res;
+
+ if (!wpa_s->last_scan_freqs || !wpa_s->num_last_scan_freqs)
+ return NULL;
+
+ len = wpa_s->num_last_scan_freqs * 8;
+ str = os_zalloc(len);
+ if (!str)
+ return NULL;
+ end = str + len;
+ pos = str;
+
+ for (i = 0; i < wpa_s->num_last_scan_freqs; i++) {
+ enum hostapd_hw_mode mode;
+ u8 op_class, channel;
+
+ mode = ieee80211_freq_to_channel_ext(wpa_s->last_scan_freqs[i],
+ 0, 0, &op_class, &channel);
+ if (mode == NUM_HOSTAPD_MODES)
+ continue;
+ if (op_class == last_op_class)
+ res = os_snprintf(pos, end - pos, ",%d", channel);
+ else
+ res = os_snprintf(pos, end - pos, "%s%d/%d",
+ pos == str ? "" : ",",
+ op_class, channel);
+ if (os_snprintf_error(end - pos, res)) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ last_op_class = op_class;
+ }
+
+ if (pos == str) {
+ os_free(str);
+ str = NULL;
+ }
+ return str;
+}
+
+
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result)
+{
+ struct wpabuf *msg;
+ const char *channel_list = NULL;
+ char *channel_list_buf = NULL;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
+
+ if (!auth || !auth->conn_status_requested)
+ return;
+ auth->conn_status_requested = 0;
+ wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d",
+ result);
+
+ if (result == DPP_STATUS_NO_AP) {
+ channel_list_buf = wpas_dpp_scan_channel_list(wpa_s);
+ channel_list = channel_list_buf;
+ }
+
+ msg = dpp_build_conn_status_result(auth, result,
+ ssid ? ssid->ssid :
+ wpa_s->dpp_last_ssid,
+ ssid ? ssid->ssid_len :
+ wpa_s->dpp_last_ssid_len,
+ channel_list);
+ os_free(channel_list_buf);
+ if (!msg) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_CONNECTION_STATUS_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+
+ /* This exchange will be terminated in the TX status handler */
+ auth->remove_on_tx_status = 1;
+
+ return;
+}
+
+
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (auth && auth->conn_status_requested)
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -182,18 +319,30 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
+ auth->connect_on_tx_status = 0;
wpa_printf(MSG_DEBUG,
"DPP: Try to connect after completed configuration result");
wpas_dpp_try_to_connect(wpa_s);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
+ if (auth->conn_status_requested) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start 15 second timeout for reporting connection status result");
+ eloop_cancel_timeout(
+ wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(
+ 15, 0, wpas_dpp_conn_status_result_timeout,
+ wpa_s, NULL);
+ } else {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
return;
}
#endif /* CONFIG_DPP2 */
if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
- "DPP: Terminate authentication exchange due to an earlier error");
+ "DPP: Terminate authentication exchange due to a request to do so on TX status");
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
@@ -899,6 +1048,9 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
}
}
+ os_memcpy(wpa_s->dpp_last_ssid, auth->ssid, auth->ssid_len);
+ wpa_s->dpp_last_ssid_len = auth->ssid_len;
+
return ssid;
fail:
wpas_notify_network_removed(wpa_s, ssid);
@@ -1452,6 +1604,9 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
status[0]);
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" status=%u", MAC2STR(src), status[0]);
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, status[0]);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -1475,6 +1630,9 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
"DPP: Network Introduction protocol resulted in failure");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
" fail=peer_connector_validation_failed", MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+#endif /* CONFIG_DPP2 */
goto fail;
}
@@ -2368,6 +2526,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 9ba315f..b337982 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -1,6 +1,7 @@
/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
+ * Copyright (c) 2018-2019, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +10,8 @@
#ifndef DPP_SUPPLICANT_H
#define DPP_SUPPLICANT_H
+enum dpp_status_error;
+
int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
@@ -26,5 +29,8 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
+void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
+ enum dpp_status_error result);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f28e439..2e083fe 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1941,6 +1941,21 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
radio_work_done(work);
}
+ os_free(wpa_s->last_scan_freqs);
+ wpa_s->last_scan_freqs = NULL;
+ wpa_s->num_last_scan_freqs = 0;
+ if (own_request && data &&
+ data->scan_info.freqs && data->scan_info.num_freqs) {
+ wpa_s->last_scan_freqs = os_malloc(sizeof(int) *
+ data->scan_info.num_freqs);
+ if (wpa_s->last_scan_freqs) {
+ os_memcpy(wpa_s->last_scan_freqs,
+ data->scan_info.freqs,
+ sizeof(int) * data->scan_info.num_freqs);
+ wpa_s->num_last_scan_freqs = data->scan_info.num_freqs;
+ }
+ }
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done:
@@ -1994,6 +2009,8 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
return 0;
}
+ wpa_s->suitable_network++;
+
if (ssid != wpa_s->current_ssid &&
wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_s->own_disconnect_req = 1;
@@ -2014,6 +2031,7 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
*/
return 1;
} else {
+ wpa_s->no_suitable_network++;
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -3066,6 +3084,10 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
return; /* P2P group removed */
wpas_auth_failed(wpa_s, "WRONG_KEY");
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s,
+ DPP_STATUS_AUTH_FAILURE);
+#endif /* CONFIG_DPP2 */
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 709a33f..6fb4efb 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -985,6 +985,10 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
+#ifdef CONFIG_DPP2
+ if (wpa_s->wpa_state == WPA_COMPLETED)
+ wpas_dpp_connected(wpa_s);
+#endif /* CONFIG_DPP2 */
}
#if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
if (update_fils_connect_params)
@@ -6079,6 +6083,7 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
}
os_free(wpa_s->ssids_from_scan_req);
+ os_free(wpa_s->last_scan_freqs);
os_free(wpa_s);
}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 32f390f..872c19c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -700,6 +700,10 @@ struct wpa_supplicant {
struct wpa_ssid_value *ssids_from_scan_req;
unsigned int num_ssids_from_scan_req;
+ int *last_scan_freqs;
+ unsigned int num_last_scan_freqs;
+ unsigned int suitable_network;
+ unsigned int no_suitable_network;
u64 drv_flags;
unsigned int drv_enc;
@@ -1237,6 +1241,8 @@ struct wpa_supplicant {
unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
+ u8 dpp_last_ssid[SSID_MAX_LEN];
+ size_t dpp_last_ssid_len;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
#endif /* CONFIG_DPP2 */