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>
This commit is contained in:
parent
b10e01a795
commit
16ef233bf1
7 changed files with 298 additions and 3 deletions
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue