/*
* wpa_supplicant - DPP
* Copyright (c) 2017, Qualcomm Atheros, Inc.
- * Copyright (c) 2018, The Linux Foundation
+ * Copyright (c) 2018-2020, The Linux Foundation
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/ip_addr.h"
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
static const u8 TRANSACTION_ID = 1;
-static struct dpp_configurator *
-dpp_configurator_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
-{
- struct dpp_configurator *conf;
-
- dl_list_for_each(conf, &wpa_s->dpp_configurator,
- struct dpp_configurator, list) {
- if (conf->id == id)
- return conf;
- }
- return NULL;
-}
-
-
-static unsigned int wpas_dpp_next_id(struct wpa_supplicant *wpa_s)
-{
- struct dpp_bootstrap_info *bi;
- unsigned int max_id = 0;
-
- dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (bi->id > max_id)
- max_id = bi->id;
- }
- return max_id + 1;
-}
-
-
/**
* wpas_dpp_qr_code - Parse and add DPP bootstrapping info from a QR Code
* @wpa_s: Pointer to wpa_supplicant data
struct dpp_bootstrap_info *bi;
struct dpp_authentication *auth = wpa_s->dpp_auth;
- bi = dpp_parse_qr_code(cmd);
+ bi = dpp_add_qr_code(wpa_s->dpp, cmd);
if (!bi)
return -1;
- bi->id = wpas_dpp_next_id(wpa_s);
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
-
if (auth && auth->response_pending &&
dpp_notify_new_qr_code(auth, bi) == 1) {
wpa_printf(MSG_DEBUG,
}
-static char * get_param(const char *cmd, const char *param)
-{
- const char *pos, *end;
- char *val;
- size_t len;
-
- pos = os_strstr(cmd, param);
- if (!pos)
- return NULL;
-
- pos += os_strlen(param);
- end = os_strchr(pos, ' ');
- if (end)
- len = end - pos;
- else
- len = os_strlen(pos);
- val = os_malloc(len + 1);
- if (!val)
- return NULL;
- os_memcpy(val, pos, len);
- val[len] = '\0';
- return val;
-}
-
-
-int wpas_dpp_bootstrap_gen(struct wpa_supplicant *wpa_s, const char *cmd)
+/**
+ * wpas_dpp_nfc_uri - Parse and add DPP bootstrapping info from NFC Tag (URI)
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @cmd: DPP URI read from a NFC Tag (URI NDEF message)
+ * Returns: Identifier of the stored info or -1 on failure
+ */
+int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd)
{
- char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
- size_t len;
- int ret = -1;
struct dpp_bootstrap_info *bi;
- bi = os_zalloc(sizeof(*bi));
+ bi = dpp_add_nfc_uri(wpa_s->dpp, cmd);
if (!bi)
- goto fail;
-
- if (os_strstr(cmd, "type=qrcode"))
- bi->type = DPP_BOOTSTRAP_QR_CODE;
- else if (os_strstr(cmd, "type=pkex"))
- bi->type = DPP_BOOTSTRAP_PKEX;
- else
- goto fail;
-
- chan = get_param(cmd, " chan=");
- mac = get_param(cmd, " mac=");
- info = get_param(cmd, " info=");
- curve = get_param(cmd, " curve=");
- key = get_param(cmd, " key=");
-
- if (key) {
- privkey_len = os_strlen(key) / 2;
- privkey = os_malloc(privkey_len);
- if (!privkey ||
- hexstr2bin(key, privkey, privkey_len) < 0)
- goto fail;
- }
-
- pk = dpp_keygen(bi, curve, privkey, privkey_len);
- if (!pk)
- goto fail;
+ return -1;
- len = 4; /* "DPP:" */
- if (chan) {
- if (dpp_parse_uri_chan_list(bi, chan) < 0)
- goto fail;
- len += 3 + os_strlen(chan); /* C:...; */
- }
- if (mac) {
- if (dpp_parse_uri_mac(bi, mac) < 0)
- goto fail;
- len += 3 + os_strlen(mac); /* M:...; */
- }
- if (info) {
- if (dpp_parse_uri_info(bi, info) < 0)
- goto fail;
- len += 3 + os_strlen(info); /* I:...; */
- }
- len += 4 + os_strlen(pk);
- bi->uri = os_malloc(len + 1);
- if (!bi->uri)
- goto fail;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
- chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
- mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
- info ? "I:" : "", info ? info : "", info ? ";" : "",
- pk);
- bi->id = wpas_dpp_next_id(wpa_s);
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
- ret = bi->id;
- bi = NULL;
-fail:
- os_free(curve);
- os_free(pk);
- os_free(chan);
- os_free(mac);
- os_free(info);
- str_clear_free(key);
- bin_clear_free(privkey, privkey_len);
- dpp_bootstrap_info_free(bi);
- return ret;
+ return bi->id;
}
-static struct dpp_bootstrap_info *
-dpp_bootstrap_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
+int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd)
{
- struct dpp_bootstrap_info *bi;
-
- dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (bi->id == id)
- return bi;
- }
- return NULL;
-}
-
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
-static int dpp_bootstrap_del(struct wpa_supplicant *wpa_s, unsigned int id)
-{
- struct dpp_bootstrap_info *bi, *tmp;
- int found = 0;
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
- dl_list_for_each_safe(bi, tmp, &wpa_s->dpp_bootstrap,
- struct dpp_bootstrap_info, list) {
- if (id && bi->id != id)
- continue;
- found = 1;
- dl_list_del(&bi->list);
- dpp_bootstrap_info_free(bi);
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Request");
+ return -1;
}
- if (id == 0)
- return 0; /* flush succeeds regardless of entries found */
- return found ? 0 : -1;
-}
-
-
-int wpas_dpp_bootstrap_remove(struct wpa_supplicant *wpa_s, const char *id)
-{
- unsigned int id_val;
-
- if (os_strcmp(id, "*") == 0) {
- id_val = 0;
- } else {
- id_val = atoi(id);
- if (id_val == 0)
- return -1;
- }
+ if (dpp_nfc_update_bi(own_bi, peer_bi) < 0)
+ return -1;
- return dpp_bootstrap_del(wpa_s, id_val);
+ return peer_bi->id;
}
-const char * wpas_dpp_bootstrap_get_uri(struct wpa_supplicant *wpa_s,
- unsigned int id)
+int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd)
{
- struct dpp_bootstrap_info *bi;
-
- bi = dpp_bootstrap_get_id(wpa_s, id);
- if (!bi)
- return NULL;
- return bi->uri;
-}
+ const char *pos;
+ struct dpp_bootstrap_info *peer_bi, *own_bi;
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!own_bi)
+ return -1;
-int wpas_dpp_bootstrap_info(struct wpa_supplicant *wpa_s, int id,
- char *reply, int reply_size)
-{
- struct dpp_bootstrap_info *bi;
+ pos = os_strstr(cmd, " uri=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos);
+ if (!peer_bi) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to parse URI from NFC Handover Select");
+ return -1;
+ }
- bi = dpp_bootstrap_get_id(wpa_s, id);
- if (!bi)
+ if (peer_bi->curve != own_bi->curve) {
+ wpa_printf(MSG_INFO,
+ "DPP: Peer (NFC Handover Selector) used different curve");
return -1;
- return os_snprintf(reply, reply_size, "type=%s\n"
- "mac_addr=" MACSTR "\n"
- "info=%s\n"
- "num_freq=%u\n"
- "curve=%s\n",
- dpp_bootstrap_type_txt(bi->type),
- MAC2STR(bi->mac_addr),
- bi->info ? bi->info : "",
- bi->num_freq,
- bi->curve->name);
+ }
+
+ return peer_bi->id;
}
}
+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;
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+#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? */
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpas_abort_ongoing_scan(wpa_s);
+ 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,
return;
}
+#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);
+ 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,
}
-static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth,
- const char *cmd)
-{
- const char *pos, *end;
- struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
- struct dpp_configurator *conf = NULL;
- u8 ssid[32] = { "test" };
- size_t ssid_len = 4;
- char pass[64] = { };
- size_t pass_len = 0;
- u8 psk[PMK_LEN];
- int psk_set = 0;
-
- if (!cmd)
- return;
-
- wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
- pos = os_strstr(cmd, " ssid=");
- if (pos) {
- pos += 6;
- end = os_strchr(pos, ' ');
- ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
- ssid_len /= 2;
- if (ssid_len > sizeof(ssid) ||
- hexstr2bin(pos, ssid, ssid_len) < 0)
- goto fail;
- }
-
- pos = os_strstr(cmd, " pass=");
- if (pos) {
- pos += 6;
- end = os_strchr(pos, ' ');
- pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
- pass_len /= 2;
- if (pass_len > sizeof(pass) - 1 || pass_len < 8 ||
- hexstr2bin(pos, (u8 *) pass, pass_len) < 0)
- goto fail;
- }
-
- pos = os_strstr(cmd, " psk=");
- if (pos) {
- pos += 5;
- if (hexstr2bin(pos, psk, PMK_LEN) < 0)
- goto fail;
- psk_set = 1;
- }
-
- if (os_strstr(cmd, " conf=sta-")) {
- conf_sta = os_zalloc(sizeof(struct dpp_configuration));
- if (!conf_sta)
- goto fail;
- os_memcpy(conf_sta->ssid, ssid, ssid_len);
- conf_sta->ssid_len = ssid_len;
- if (os_strstr(cmd, " conf=sta-psk") ||
- os_strstr(cmd, " conf=sta-sae") ||
- os_strstr(cmd, " conf=sta-psk-sae")) {
- if (os_strstr(cmd, " conf=sta-psk-sae"))
- conf_sta->akm = DPP_AKM_PSK_SAE;
- else if (os_strstr(cmd, " conf=sta-sae"))
- conf_sta->akm = DPP_AKM_SAE;
- else
- conf_sta->akm = DPP_AKM_PSK;
- if (psk_set) {
- os_memcpy(conf_sta->psk, psk, PMK_LEN);
- } else {
- conf_sta->passphrase = os_strdup(pass);
- if (!conf_sta->passphrase)
- goto fail;
- }
- } else if (os_strstr(cmd, " conf=sta-dpp")) {
- conf_sta->akm = DPP_AKM_DPP;
- } else {
- goto fail;
- }
- }
-
- if (os_strstr(cmd, " conf=ap-")) {
- conf_ap = os_zalloc(sizeof(struct dpp_configuration));
- if (!conf_ap)
- goto fail;
- os_memcpy(conf_ap->ssid, ssid, ssid_len);
- conf_ap->ssid_len = ssid_len;
- if (os_strstr(cmd, " conf=ap-psk") ||
- os_strstr(cmd, " conf=ap-sae") ||
- os_strstr(cmd, " conf=ap-psk-sae")) {
- if (os_strstr(cmd, " conf=ap-psk-sae"))
- conf_ap->akm = DPP_AKM_PSK_SAE;
- else if (os_strstr(cmd, " conf=ap-sae"))
- conf_ap->akm = DPP_AKM_SAE;
- else
- conf_ap->akm = DPP_AKM_PSK;
- if (psk_set) {
- os_memcpy(conf_ap->psk, psk, PMK_LEN);
- } else {
- conf_ap->passphrase = os_strdup(pass);
- if (!conf_ap->passphrase)
- goto fail;
- }
- } else if (os_strstr(cmd, " conf=ap-dpp")) {
- conf_ap->akm = DPP_AKM_DPP;
- } else {
- goto fail;
- }
- }
-
- pos = os_strstr(cmd, " expiry=");
- if (pos) {
- long int val;
-
- pos += 8;
- val = strtol(pos, NULL, 0);
- if (val <= 0)
- goto fail;
- if (conf_sta)
- conf_sta->netaccesskey_expiry = val;
- if (conf_ap)
- conf_ap->netaccesskey_expiry = val;
- }
-
- pos = os_strstr(cmd, " configurator=");
- if (pos) {
- pos += 14;
- conf = dpp_configurator_get_id(wpa_s, atoi(pos));
- if (!conf) {
- wpa_printf(MSG_INFO,
- "DPP: Could not find the specified configurator");
- goto fail;
- }
- }
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
- auth->conf = conf;
- return;
-
-fail:
- wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
- dpp_configuration_free(conf_sta);
- dpp_configuration_free(conf_ap);
-}
-
-
static void wpas_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
{
const char *pos;
struct dpp_bootstrap_info *peer_bi, *own_bi = NULL;
+ struct dpp_authentication *auth;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
unsigned int neg_freq = 0;
+ int tcp = 0;
+#ifdef CONFIG_DPP2
+ int tcp_port = DPP_TCP_PORT;
+ struct hostapd_ip_addr ipaddr;
+ char *addr;
+#endif /* CONFIG_DPP2 */
wpa_s->dpp_gas_client = 0;
if (!pos)
return -1;
pos += 6;
- peer_bi = dpp_bootstrap_get_id(wpa_s, atoi(pos));
+ peer_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
if (!peer_bi) {
wpa_printf(MSG_INFO,
"DPP: Could not find bootstrapping info for the identified peer");
return -1;
}
+#ifdef CONFIG_DPP2
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ tcp_port = atoi(pos);
+ }
+
+ addr = get_param(cmd, " tcp_addr=");
+ if (addr) {
+ int res;
+
+ res = hostapd_parse_ip_addr(addr, &ipaddr);
+ os_free(addr);
+ if (res)
+ return -1;
+ tcp = 1;
+ }
+#endif /* CONFIG_DPP2 */
+
pos = os_strstr(cmd, " own=");
if (pos) {
pos += 5;
- own_bi = dpp_bootstrap_get_id(wpa_s, atoi(pos));
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
if (!own_bi) {
wpa_printf(MSG_INFO,
"DPP: Could not find bootstrapping info for the identified local entry");
pos = os_strstr(cmd, " netrole=");
if (pos) {
pos += 9;
- wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+ if (os_strncmp(pos, "ap", 2) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strncmp(pos, "configurator", 12) == 0)
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
+ } else {
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
}
pos = os_strstr(cmd, " neg_freq=");
if (pos)
neg_freq = atoi(pos + 10);
- if (wpa_s->dpp_auth) {
+ if (!tcp && wpa_s->dpp_auth) {
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,
NULL);
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
}
- wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles,
- neg_freq,
- wpa_s->hw.modes, wpa_s->hw.num_modes);
- if (!wpa_s->dpp_auth)
+
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles,
+ neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes);
+ if (!auth)
goto fail;
- wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd);
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, cmd) < 0) {
+ dpp_auth_deinit(auth);
+ goto fail;
+ }
- wpa_s->dpp_auth->neg_freq = neg_freq;
+ auth->neg_freq = neg_freq;
if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(wpa_s->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
- ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+#ifdef CONFIG_DPP2
+ if (tcp)
+ return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+#endif /* CONFIG_DPP2 */
+ wpa_s->dpp_auth = auth;
return wpas_dpp_auth_init_next(wpa_s);
fail:
return -1;
wpa_printf(MSG_DEBUG,
"DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
lwork->freq);
+ wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
wpa_s->dpp_pending_listen_freq = 0;
return;
wpa_s->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR |
DPP_CAPAB_ENROLLEE;
wpa_s->dpp_qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
- wpa_s->dpp_netrole_ap = os_strstr(cmd, " netrole=ap") != NULL;
+ if (os_strstr(cmd, " netrole=ap"))
+ wpa_s->dpp_netrole = DPP_NETROLE_AP;
+ else if (os_strstr(cmd, " netrole=configurator"))
+ wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR;
+ else
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
if (wpa_s->dpp_listen_freq == (unsigned int) freq) {
wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
freq);
}
-void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq)
-{
- if (!wpa_s->dpp_listen_freq && !wpa_s->dpp_pending_listen_freq)
- return;
-
- wpa_printf(MSG_DEBUG,
- "DPP: remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u)",
- wpa_s->off_channel_freq, wpa_s->dpp_pending_listen_freq,
- wpa_s->roc_waiting_drv_freq, freq);
- if (wpa_s->off_channel_freq &&
- wpa_s->off_channel_freq == wpa_s->dpp_pending_listen_freq) {
- wpa_printf(MSG_DEBUG, "DPP: Listen on %u MHz started", freq);
- wpa_s->dpp_pending_listen_freq = 0;
- } else {
- wpa_printf(MSG_DEBUG,
- "DPP: Ignore remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d freq=%u)",
- wpa_s->off_channel_freq,
- wpa_s->dpp_pending_listen_freq, freq);
- }
-}
-
-
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
{
const u8 *r_bootstrap, *i_bootstrap;
u16 r_bootstrap_len, i_bootstrap_len;
- struct dpp_bootstrap_info *bi, *own_bi = NULL, *peer_bi = NULL;
+ struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
+
+ if (!wpa_s->dpp)
+ return;
wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
MAC2STR(src));
+#ifdef CONFIG_DPP2
+ wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
+
r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
&r_bootstrap_len);
if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
/* Try to find own and peer bootstrapping key matches based on the
* received hash values */
- dl_list_for_each(bi, &wpa_s->dpp_bootstrap, struct dpp_bootstrap_info,
- list) {
- if (!own_bi && bi->own &&
- os_memcmp(bi->pubkey_hash, r_bootstrap,
- SHA256_MAC_LEN) == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Found matching own bootstrapping information");
- own_bi = bi;
- }
-
- if (!peer_bi && !bi->own &&
- os_memcmp(bi->pubkey_hash, i_bootstrap,
- SHA256_MAC_LEN) == 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Found matching peer bootstrapping information");
- peer_bi = bi;
- }
-
- if (own_bi && peer_bi)
- break;
- }
-
+ dpp_bootstrap_find_pair(wpa_s->dpp, i_bootstrap, r_bootstrap,
+ &own_bi, &peer_bi);
if (!own_bi) {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
"No matching own bootstrapping key found - ignore message");
wpa_s->dpp_gas_client = 0;
wpa_s->dpp_auth_ok_on_ack = 0;
- wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles,
+ wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s,
+ wpa_s->dpp_allowed_roles,
wpa_s->dpp_qr_mutual,
peer_bi, own_bi, freq, hdr, buf, len);
if (!wpa_s->dpp_auth) {
return;
}
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth,
- wpa_s->dpp_configurator_params);
+ if (dpp_set_configurator(wpa_s->dpp_auth,
+ wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
if (wpa_s->dpp_listen_freq &&
static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
+#ifdef CONFIG_DPP2
+ if (conf->akm == DPP_AKM_SAE) {
+#ifdef CONFIG_SAE
+ struct wpa_driver_capa capa;
+ int res;
+
+ res = wpa_drv_get_capa(wpa_s, &capa);
+ if (res == 0 &&
+ !(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: SAE not supported by the driver");
+ return NULL;
+ }
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
+ return NULL;
+#endif /* CONFIG_SAE */
+ }
+#endif /* CONFIG_DPP2 */
+
ssid = wpa_config_add_network(wpa_s->conf);
if (!ssid)
return NULL;
wpa_config_set_network_defaults(ssid);
ssid->disabled = 1;
- ssid->ssid = os_malloc(auth->ssid_len);
+ ssid->ssid = os_malloc(conf->ssid_len);
if (!ssid->ssid)
goto fail;
- os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
- ssid->ssid_len = auth->ssid_len;
+ os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
+ ssid->ssid_len = conf->ssid_len;
- if (auth->connector) {
- ssid->key_mgmt = WPA_KEY_MGMT_DPP;
- ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->dpp_connector = os_strdup(auth->connector);
+ if (conf->connector) {
+ if (dpp_akm_dpp(conf->akm)) {
+ ssid->key_mgmt = WPA_KEY_MGMT_DPP;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ }
+ ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
}
- if (auth->c_sign_key) {
- ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (conf->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
if (!ssid->dpp_csign)
goto fail;
- os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
- ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
if (auth->net_access_key) {
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector) {
- ssid->key_mgmt = 0;
- if (auth->akm == DPP_AKM_PSK || auth->akm == DPP_AKM_PSK_SAE)
+ if (!conf->connector || dpp_akm_psk(conf->akm) ||
+ dpp_akm_sae(conf->akm)) {
+ if (!conf->connector || !dpp_akm_dpp(conf->akm))
+ ssid->key_mgmt = 0;
+ if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
- if (auth->akm == DPP_AKM_SAE || auth->akm == DPP_AKM_PSK_SAE)
+ if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
- if (auth->passphrase[0]) {
+ if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
- auth->passphrase) < 0)
+ conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
} else {
- ssid->psk_set = auth->psk_set;
- os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ ssid->psk_set = conf->psk_set;
+ os_memcpy(ssid->psk, conf->psk, PMK_LEN);
}
}
+ os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
+
return ssid;
fail:
wpas_notify_network_removed(wpa_s, ssid);
}
-static void wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
- return;
+ return 0;
- ssid = wpas_dpp_add_network(wpa_s, auth);
+ ssid = wpas_dpp_add_network(wpa_s, auth, conf);
if (!ssid)
- return;
+ return -1;
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
+ if (wpa_s->conf->dpp_config_processing == 2)
+ ssid->disabled = 0;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+ return 0;
+}
+
+
+static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
if (wpa_s->conf->dpp_config_processing < 2)
return;
- wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
- ssid->disabled = 0;
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_s->scan_runs = 0;
- wpa_s->normal_scans = 0;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
+ auth->connect_on_tx_status = 1;
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
+ wpas_dpp_try_to_connect(wpa_s);
}
-static void wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
- if (auth->ssid_len)
+ if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->ssid_charset)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID_CHARSET "%d",
+ conf->ssid_charset);
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
+ conf->connector);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
hex);
os_free(hex);
}
}
- wpas_dpp_process_config(wpa_s, auth);
+ return wpas_dpp_process_config(wpa_s, auth, conf);
+}
+
+
+static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
+ struct dpp_asymmetric_key *key)
+{
+#ifdef CONFIG_DPP2
+ int res;
+
+ if (!key)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+
+ while (key) {
+ res = dpp_configurator_from_backup(wpa_s->dpp, key);
+ if (res < 0)
+ return -1;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d",
+ res);
+ key = key->next;
+ }
+#endif /* CONFIG_DPP2 */
+
+ return 0;
}
struct wpa_supplicant *wpa_s = ctx;
const u8 *pos;
struct dpp_authentication *auth = wpa_s->dpp_auth;
+ int res;
+ enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ unsigned int i;
wpa_s->dpp_gas_dialog_token = -1;
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return;
}
- if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ if (result != GAS_QUERY_SUCCESS ||
+ !resp || status_code != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
goto fail;
}
goto fail;
}
- wpas_dpp_handle_config_obj(wpa_s, auth);
- dpp_auth_deinit(wpa_s->dpp_auth);
- wpa_s->dpp_auth = NULL;
- return;
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res < 0)
+ goto fail;
+ }
+ if (auth->num_conf_obj)
+ wpas_dpp_post_process_config(wpa_s, auth);
+ if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0)
+ goto fail;
+ status = DPP_STATUS_OK;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_REJECT_CONFIG) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - Reject Config Object");
+ status = DPP_STATUS_CONFIG_REJECTED;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
fail:
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ if (status != DPP_STATUS_OK)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+#ifdef CONFIG_DPP2
+ if (auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ struct wpabuf *msg;
+
+ wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
+ msg = dpp_build_conf_result(auth, status);
+ if (!msg)
+ goto fail2;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(addr), auth->curr_freq,
+ DPP_PA_CONFIGURATION_RESULT);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ 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 */
+ return;
+ }
+fail2:
+#endif /* CONFIG_DPP2 */
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
}
static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
- struct wpabuf *buf, *conf_req;
- char json[100];
+ struct wpabuf *buf;
int res;
+ int *supp_op_classes;
wpa_s->dpp_gas_client = 1;
- os_snprintf(json, sizeof(json),
- "{\"name\":\"Test\","
- "\"wi-fi_tech\":\"infra\","
- "\"netRole\":\"%s\"}",
- wpa_s->dpp_netrole_ap ? "ap" : "sta");
-#ifdef CONFIG_TESTING_OPTIONS
- if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
- wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
- json[29] = 'k'; /* replace "infra" with "knfra" */
- }
-#endif /* CONFIG_TESTING_OPTIONS */
- wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
-
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- conf_req = dpp_build_conf_req(auth, json);
- if (!conf_req) {
+ supp_op_classes = wpas_supp_op_classes(wpa_s);
+ buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
+ wpa_s->dpp_netrole,
+ wpa_s->conf->dpp_mud_url,
+ supp_op_classes);
+ os_free(supp_op_classes);
+ if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
return;
}
- buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
- if (!buf) {
- wpabuf_free(conf_req);
- return;
- }
-
- /* Advertisement Protocol IE */
- wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
- wpabuf_put_u8(buf, 8); /* Length */
- wpabuf_put_u8(buf, 0x7f);
- wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
- wpabuf_put_u8(buf, 5);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, DPP_OUI_TYPE);
- wpabuf_put_u8(buf, 0x01);
-
- /* GAS Query */
- wpabuf_put_le16(buf, wpabuf_len(conf_req));
- wpabuf_put_buf(buf, conf_req);
- wpabuf_free(conf_req);
-
wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (freq %u MHz)",
MAC2STR(auth->peer_mac_addr), auth->curr_freq);
wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
return;
}
- os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ src, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 500, wpas_dpp_tx_status, 0);
+ wpabuf_free(msg);
+ wpa_s->dpp_auth_ok_on_ack = 1;
+}
+
+
+static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Authentication in progress - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ return;
+ }
+
+ wpas_dpp_auth_success(wpa_s, 0);
+}
+
+
+#ifdef CONFIG_DPP2
+
+static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conf_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Configuration Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_conn_status_result)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Timeout while waiting for Connection Status Result");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT "timeout");
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+}
+
+
+static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
+ MAC2STR(src));
+
+ if (!auth || !auth->waiting_conf_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for result - drop");
+ return;
+ }
+
+ if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
+ MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ return;
+ }
+
+ status = dpp_conf_result_rx(auth, hdr, buf, len);
+
+ if (status == DPP_STATUS_OK && auth->send_conn_status) {
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ auth->waiting_conn_status_result = 1;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(16, 0,
+ wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq :
+ auth->curr_freq);
+ return;
+ }
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ if (status == DPP_STATUS_OK)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+}
+
+
+static void wpas_dpp_rx_conn_status_result(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ enum dpp_status_error status;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len = 0;
+ char *channel_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
+
+ if (!auth || !auth->waiting_conn_status_result) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No DPP Configuration waiting for connection status result - drop");
+ return;
+ }
+
+ status = dpp_conn_status_result_rx(auth, hdr, buf, len,
+ ssid, &ssid_len, &channel_list);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONN_STATUS_RESULT
+ "result=%d ssid=%s channel_list=%s",
+ status, wpa_ssid_txt(ssid, ssid_len),
+ channel_list ? channel_list : "N/A");
+ os_free(channel_list);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ dpp_auth_deinit(auth);
+ wpa_s->dpp_auth = NULL;
+ eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
+ wpa_s, NULL);
+}
+
+
+static int wpas_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ unsigned int i;
+ int res = -1;
+
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res)
+ break;
+ }
+ if (!res)
+ wpas_dpp_post_process_config(wpa_s, auth);
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
- MAC2STR(src), auth->curr_freq, DPP_PA_AUTHENTICATION_CONF);
- offchannel_send_action(wpa_s, auth->curr_freq,
- src, wpa_s->own_addr, broadcast,
- wpabuf_head(msg), wpabuf_len(msg),
- 500, wpas_dpp_tx_status, 0);
- wpabuf_free(msg);
- wpa_s->dpp_auth_ok_on_ack = 1;
+ return res;
}
-static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
- const u8 *hdr, const u8 *buf, size_t len)
+static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
{
- struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpa_supplicant *wpa_s = ctx;
- wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
- MAC2STR(src));
+ if (bi == wpa_s->dpp_chirp_bi)
+ wpas_dpp_chirp_stop(wpa_s);
+}
- if (!auth) {
+
+static void
+wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_bootstrap;
+ u16 r_bootstrap_len;
+ struct dpp_bootstrap_info *peer_bi;
+ struct dpp_authentication *auth;
+
+ if (!wpa_s->dpp)
+ return;
+
+ if (wpa_s->dpp_auth) {
wpa_printf(MSG_DEBUG,
- "DPP: No DPP Authentication in progress - drop");
+ "DPP: Ignore Presence Announcement during ongoing Authentication");
return;
}
- if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
- MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
+ wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR,
+ MAC2STR(src));
+
+ r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_bootstrap_len);
+ if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_bootstrap, r_bootstrap_len);
+ peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap);
+ if (!peer_bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No matching bootstrapping information found");
return;
}
- if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
- wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
+ auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
+ DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
+ if (!auth)
+ return;
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(auth);
return;
}
- wpas_dpp_auth_success(wpa_s, 0);
+ auth->neg_freq = freq;
+
+ if (!is_zero_ether_addr(peer_bi->mac_addr))
+ os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+
+ wpa_s->dpp_auth = auth;
+ if (wpas_dpp_auth_init_next(wpa_s) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ }
}
+#endif /* CONFIG_DPP2 */
+
static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
const u8 *src,
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;
}
"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;
}
wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer,
unsigned int freq)
{
- struct dpp_pkex *pkex = wpa_s->dpp_pkex;
struct dpp_bootstrap_info *bi;
- bi = os_zalloc(sizeof(*bi));
+ bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
if (!bi)
return NULL;
- bi->id = wpas_dpp_next_id(wpa_s);
- bi->type = DPP_BOOTSTRAP_PKEX;
- os_memcpy(bi->mac_addr, peer, ETH_ALEN);
- bi->num_freq = 1;
- bi->freq[0] = freq;
- bi->curve = pkex->own_bi->curve;
- bi->pubkey = pkex->peer_bootstrap_key;
- pkex->peer_bootstrap_key = NULL;
- dpp_pkex_free(pkex);
wpa_s->dpp_pkex = NULL;
- if (dpp_bootstrap_key_hash(bi) < 0) {
- dpp_bootstrap_info_free(bi);
- return NULL;
- }
- dl_list_add(&wpa_s->dpp_bootstrap, &bi->list);
return bi;
}
if (wpas_dpp_auth_init(wpa_s, cmd) < 0) {
wpa_printf(MSG_DEBUG,
"DPP: Authentication initialization failed");
+ offchannel_send_action_done(wpa_s);
return;
}
}
wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
freq);
break;
+#ifdef CONFIG_DPP2
+ case DPP_PA_CONFIGURATION_RESULT:
+ wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
+ break;
+ case DPP_PA_CONNECTION_STATUS_RESULT:
+ wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len);
+ break;
+ case DPP_PA_PRESENCE_ANNOUNCEMENT:
+ wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len,
+ freq);
+ break;
+#endif /* CONFIG_DPP2 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return NULL;
}
+
+ if (wpa_s->dpp_auth_ok_on_ack && auth->configurator) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Have not received ACK for Auth Confirm yet - assume it was received based on this GAS request");
+ /* wpas_dpp_auth_success() would normally have been called from
+ * TX status handler, but since there was no such handler call
+ * yet, simply send out the event message and proceed with
+ * exchange. */
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
+ wpa_s->dpp_auth_ok_on_ack = 0;
+ }
+
wpa_hexdump(MSG_DEBUG,
"DPP: Received Configuration Request (GAS Query Request)",
query, query_len);
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP2
+ if (ok && auth->peer_version >= 2 &&
+ auth->conf_resp_status == DPP_STATUS_OK) {
+ wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
+ auth->waiting_conf_result = 1;
+ auth->conf_resp = NULL;
+ wpabuf_free(resp);
+ eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(2, 0,
+ wpas_dpp_config_result_wait_timeout,
+ wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (ok)
}
-static unsigned int wpas_dpp_next_configurator_id(struct wpa_supplicant *wpa_s)
-{
- struct dpp_configurator *conf;
- unsigned int max_id = 0;
-
- dl_list_for_each(conf, &wpa_s->dpp_configurator,
- struct dpp_configurator, list) {
- if (conf->id > max_id)
- max_id = conf->id;
- }
- return max_id + 1;
-}
-
-
-int wpas_dpp_configurator_add(struct wpa_supplicant *wpa_s, const char *cmd)
-{
- char *curve = NULL;
- char *key = NULL;
- u8 *privkey = NULL;
- size_t privkey_len = 0;
- int ret = -1;
- struct dpp_configurator *conf = NULL;
-
- curve = get_param(cmd, " curve=");
- key = get_param(cmd, " key=");
-
- if (key) {
- privkey_len = os_strlen(key) / 2;
- privkey = os_malloc(privkey_len);
- if (!privkey ||
- hexstr2bin(key, privkey, privkey_len) < 0)
- goto fail;
- }
-
- conf = dpp_keygen_configurator(curve, privkey, privkey_len);
- if (!conf)
- goto fail;
-
- conf->id = wpas_dpp_next_configurator_id(wpa_s);
- dl_list_add(&wpa_s->dpp_configurator, &conf->list);
- ret = conf->id;
- conf = NULL;
-fail:
- os_free(curve);
- str_clear_free(key);
- bin_clear_free(privkey, privkey_len);
- dpp_configurator_free(conf);
- return ret;
-}
-
-
-static int dpp_configurator_del(struct wpa_supplicant *wpa_s, unsigned int id)
-{
- struct dpp_configurator *conf, *tmp;
- int found = 0;
-
- dl_list_for_each_safe(conf, tmp, &wpa_s->dpp_configurator,
- struct dpp_configurator, list) {
- if (id && conf->id != id)
- continue;
- found = 1;
- dl_list_del(&conf->list);
- dpp_configurator_free(conf);
- }
-
- if (id == 0)
- return 0; /* flush succeeds regardless of entries found */
- return found ? 0 : -1;
-}
-
-
-int wpas_dpp_configurator_remove(struct wpa_supplicant *wpa_s, const char *id)
-{
- unsigned int id_val;
-
- if (os_strcmp(id, "*") == 0) {
- id_val = 0;
- } else {
- id_val = atoi(id);
- if (id_val == 0)
- return -1;
- }
-
- return dpp_configurator_del(wpa_s, id_val);
-}
-
-
int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
{
struct dpp_authentication *auth;
int ret = -1;
char *curve = NULL;
- auth = os_zalloc(sizeof(*auth));
+ auth = dpp_alloc_auth(wpa_s->dpp, wpa_s);
if (!auth)
return -1;
curve = get_param(cmd, " curve=");
- wpas_dpp_set_configurator(wpa_s, auth, cmd);
-
- if (dpp_configurator_own_config(auth, curve, 0) == 0) {
- wpas_dpp_handle_config_obj(wpa_s, auth);
- ret = 0;
- }
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (dpp_set_configurator(auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 0) == 0)
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[0]);
+ if (!ret)
+ wpas_dpp_post_process_config(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
}
-int wpas_dpp_configurator_get_key(struct wpa_supplicant *wpa_s, unsigned int id,
- char *buf, size_t buflen)
-{
- struct dpp_configurator *conf;
-
- conf = dpp_configurator_get_id(wpa_s, id);
- if (!conf)
- return -1;
-
- return dpp_configurator_get_key(conf, buf, buflen);
-}
-
-
static void
wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
struct os_time now;
struct wpabuf *msg;
unsigned int wait_time;
+ const u8 *rsn;
+ struct wpa_ie_data ied;
if (!(ssid->key_mgmt & WPA_KEY_MGMT_DPP) || !bss)
return 0; /* Not using DPP AKM - continue */
+ rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+ !(ied.key_mgmt & WPA_KEY_MGMT_DPP))
+ return 0; /* AP does not support DPP AKM - continue */
if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
return 0; /* PMKSA exists for DPP AKM - continue */
if (!pos)
return -1;
pos += 5;
- own_bi = dpp_bootstrap_get_id(wpa_s, atoi(pos));
+ own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
if (!own_bi) {
wpa_printf(MSG_DEBUG,
"DPP: Identified bootstrap info not found");
void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
+ offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
dpp_pkex_free(wpa_s->dpp_pkex);
int wpas_dpp_init(struct wpa_supplicant *wpa_s)
{
+ struct dpp_global_config config;
u8 adv_proto_id[7];
adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
sizeof(adv_proto_id), wpas_dpp_gas_req_handler,
wpas_dpp_gas_status_handler, wpa_s) < 0)
return -1;
- dl_list_init(&wpa_s->dpp_bootstrap);
- dl_list_init(&wpa_s->dpp_configurator);
- wpa_s->dpp_init_done = 1;
- return 0;
+
+ os_memset(&config, 0, sizeof(config));
+ config.msg_ctx = wpa_s;
+ config.cb_ctx = wpa_s;
+#ifdef CONFIG_DPP2
+ config.process_conf_obj = wpas_dpp_process_conf_obj;
+ config.remove_bi = wpas_dpp_remove_bi;
+#endif /* CONFIG_DPP2 */
+ wpa_s->dpp = dpp_global_init(&config);
+ return wpa_s->dpp ? 0 : -1;
}
wpa_s->dpp_groups_override = NULL;
wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
#endif /* CONFIG_TESTING_OPTIONS */
- if (!wpa_s->dpp_init_done)
+ if (!wpa_s->dpp)
return;
+ dpp_global_clear(wpa_s->dpp);
eloop_cancel_timeout(wpas_dpp_pkex_retry_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP2
+ 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;
+ wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
- dpp_bootstrap_del(wpa_s, 0);
- dpp_configurator_del(wpa_s, 0);
wpas_dpp_stop(wpa_s);
wpas_dpp_pkex_remove(wpa_s, "*");
os_memset(wpa_s->dpp_intro_bssid, 0, ETH_ALEN);
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = NULL;
}
+
+
+#ifdef CONFIG_DPP2
+
+int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ struct dpp_controller_config config;
+ const char *pos;
+
+ os_memset(&config, 0, sizeof(config));
+ if (cmd) {
+ pos = os_strstr(cmd, " tcp_port=");
+ if (pos) {
+ pos += 10;
+ config.tcp_port = atoi(pos);
+ }
+ }
+ config.configurator_params = wpa_s->dpp_configurator_params;
+ return dpp_controller_start(wpa_s->dpp, &config);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_chirp_next(wpa_s, NULL);
+}
+
+
+static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
+ wpa_s->dpp_chirp_freq);
+ if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
+ if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
+ wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), wpa_s->dpp_chirp_freq,
+ DPP_PA_PRESENCE_ANNOUNCEMENT);
+ if (offchannel_send_action(
+ wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(wpa_s->dpp_presence_announcement),
+ wpabuf_len(wpa_s->dpp_presence_announcement),
+ 2000, wpas_dpp_chirp_tx_status, 0) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+ unsigned int i;
+ struct hostapd_hw_modes *mode;
+ int c;
+ struct wpa_bss *bss;
+
+ if (!bi)
+ return;
+
+ wpa_s->dpp_chirp_scan_done = 1;
+
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+
+ /* Channels from own bootstrapping info */
+ for (i = 0; i < bi->num_freq; i++)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]);
+
+ /* Preferred chirping channels */
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211A, 0);
+ if (mode) {
+ int chan44 = 0, chan149 = 0;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ continue;
+ if (chan->freq == 5220)
+ chan44 = 1;
+ if (chan->freq == 5745)
+ chan149 = 1;
+ }
+ if (chan149)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+ else if (chan44)
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+ }
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211AD, 0);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR)) ||
+ chan->freq != 60480)
+ continue;
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+ break;
+ }
+ }
+
+ /* Add channels from scan results for APs that advertise Configurator
+ * Connectivity element */
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
+ int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+ bss->freq);
+ }
+
+ if (!wpa_s->dpp_chirp_freqs ||
+ eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
+ wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int i;
+
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+
+ if (wpa_s->dpp_chirp_freq == 0) {
+ if (wpa_s->dpp_chirp_round % 4 == 0 &&
+ !wpa_s->dpp_chirp_scan_done) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update channel list for chirping");
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->scan_res_handler =
+ wpas_dpp_chirp_scan_res_handler;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
+ wpa_s->dpp_chirp_round++;
+ wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+ wpa_s->dpp_chirp_round);
+ } else {
+ for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
+ if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
+ break;
+ if (!wpa_s->dpp_chirp_freqs[i]) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Previous chirp freq %d not found",
+ wpa_s->dpp_chirp_freq);
+ return;
+ }
+ i++;
+ if (wpa_s->dpp_chirp_freqs[i]) {
+ wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
+ } else {
+ wpa_s->dpp_chirp_iter--;
+ if (wpa_s->dpp_chirp_iter <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Chirping iterations completed");
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ wpa_s->dpp_chirp_freq = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_chirp_stop(wpa_s);
+ return;
+ }
+ if (wpa_s->dpp_chirp_listen) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Listen on %d MHz during chirp 30 second wait",
+ wpa_s->dpp_chirp_listen);
+ wpas_dpp_listen_start(wpa_s,
+ wpa_s->dpp_chirp_listen);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait 30 seconds before starting the next chirping round");
+ }
+ return;
+ }
+ }
+
+ wpas_dpp_chirp_start(wpa_s);
+}
+
+
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ const char *pos;
+ int iter = 1, listen_freq = 0;
+ struct dpp_bootstrap_info *bi;
+
+ pos = os_strstr(cmd, " own=");
+ if (!pos)
+ return -1;
+ pos += 5;
+ bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+ if (!bi) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Identified bootstrap info not found");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " listen=");
+ if (pos) {
+ listen_freq = atoi(pos + 8);
+ if (iter <= 0)
+ return -1;
+ }
+
+ wpas_dpp_chirp_stop(wpa_s);
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_chirp_bi = bi;
+ wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+ if (!wpa_s->dpp_presence_announcement)
+ return -1;
+ wpa_s->dpp_chirp_iter = iter;
+ wpa_s->dpp_chirp_round = 0;
+ wpa_s->dpp_chirp_scan_done = 0;
+ wpa_s->dpp_chirp_listen = listen_freq;
+
+ return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->dpp_presence_announcement) {
+ offchannel_send_action_done(wpa_s);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+ }
+ wpa_s->dpp_chirp_bi = NULL;
+ wpabuf_free(wpa_s->dpp_presence_announcement);
+ wpa_s->dpp_presence_announcement = NULL;
+ if (wpa_s->dpp_chirp_listen)
+ wpas_dpp_listen_stop(wpa_s);
+ wpa_s->dpp_chirp_listen = 0;
+ wpa_s->dpp_chirp_freq = 0;
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = NULL;
+ eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
+ if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
+ wpas_abort_ongoing_scan(wpa_s);
+ wpa_s->scan_res_handler = NULL;
+ }
+}
+
+#endif /* CONFIG_DPP2 */