aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2017-06-15 18:18:15 (GMT)
committerJouni Malinen <j@w1.fi>2017-06-19 18:13:15 (GMT)
commit461d39af40d0a83877439d029392f4401b4399ac (patch)
treee0c07154e7660bb2c1b0d72b9013ba557767a3ca /wpa_supplicant
parent30d27b048ea257d6fea5709021b2b3cf9a1e1849 (diff)
downloadhostap-461d39af40d0a83877439d029392f4401b4399ac.zip
hostap-461d39af40d0a83877439d029392f4401b4399ac.tar.gz
hostap-461d39af40d0a83877439d029392f4401b4399ac.tar.bz2
DPP: Configuration exchange
This adds support for DPP Configuration Protocol using GAS. Full generation and processing of the configuration object is not included in this commit. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/Android.mk8
-rw-r--r--wpa_supplicant/Makefile8
-rw-r--r--wpa_supplicant/ctrl_iface.c31
-rw-r--r--wpa_supplicant/dpp_supplicant.c508
-rw-r--r--wpa_supplicant/dpp_supplicant.h2
-rw-r--r--wpa_supplicant/events.c10
-rw-r--r--wpa_supplicant/wpa_supplicant.c46
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h12
8 files changed, 617 insertions, 8 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 509a880..bc05417 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -254,6 +254,8 @@ NEED_HMAC_SHA512_KDF=y
NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_JSON=y
+NEED_GAS_SERVER=y
endif
ifdef CONFIG_OWE
@@ -1566,6 +1568,12 @@ OBJS += src/utils/ext_password.c
L_CFLAGS += -DCONFIG_EXT_PASSWORD
endif
+ifdef NEED_GAS_SERVER
+OBJS += src/common/gas_server.c
+L_CFLAGS += -DCONFIG_GAS_SERVER
+NEED_GAS=y
+endif
+
ifdef NEED_GAS
OBJS += src/common/gas.c
OBJS += gas_query.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 3a25954..46410de 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -287,6 +287,8 @@ NEED_HMAC_SHA512_KDF=y
NEED_SHA256=y
NEED_SHA384=y
NEED_SHA512=y
+NEED_JSON=y
+NEED_GAS_SERVER=y
endif
ifdef CONFIG_OWE
@@ -1692,6 +1694,12 @@ OBJS += ../src/utils/ext_password.o
CFLAGS += -DCONFIG_EXT_PASSWORD
endif
+ifdef NEED_GAS_SERVER
+OBJS += ../src/common/gas_server.o
+CFLAGS += -DCONFIG_GAS_SERVER
+NEED_GAS=y
+endif
+
ifdef NEED_GAS
OBJS += ../src/common/gas.o
OBJS += gas_query.o
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 247fd64..d8363a4 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -608,6 +608,23 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->get_pref_freq_list_override = NULL;
else
wpa_s->get_pref_freq_list_override = os_strdup(value);
+#ifdef CONFIG_DPP
+ } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
+ os_free(wpa_s->dpp_config_obj_override);
+ wpa_s->dpp_config_obj_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_discovery_override") == 0) {
+ os_free(wpa_s->dpp_discovery_override);
+ wpa_s->dpp_discovery_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_groups_override") == 0) {
+ os_free(wpa_s->dpp_groups_override);
+ wpa_s->dpp_groups_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd, "dpp_devices_override") == 0) {
+ os_free(wpa_s->dpp_devices_override);
+ wpa_s->dpp_devices_override = os_strdup(value);
+ } else if (os_strcasecmp(cmd,
+ "dpp_ignore_netaccesskey_mismatch") == 0) {
+ wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
@@ -10199,6 +10216,20 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = -1;
} else if (os_strcmp(buf, "DPP_STOP_LISTEN") == 0) {
wpas_dpp_listen_stop(wpa_s);
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_ADD", 20) == 0) {
+ int res;
+
+ res = wpas_dpp_configurator_add(wpa_s, buf + 20);
+ if (res < 0) {
+ reply_len = -1;
+ } else {
+ reply_len = os_snprintf(reply, reply_size, "%d", res);
+ if (os_snprintf_error(reply_size, reply_len))
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
+ if (wpas_dpp_configurator_remove(wpa_s, buf + 24) < 0)
+ reply_len = -1;
#endif /* CONFIG_DPP */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 8cae248..848621a 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -11,14 +11,19 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/dpp.h"
+#include "common/gas.h"
+#include "common/gas_server.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "offchannel.h"
+#include "gas_query.h"
#include "dpp_supplicant.h"
static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
unsigned int freq);
+static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator);
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -28,6 +33,20 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+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;
@@ -273,11 +292,16 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG,
"DPP: Terminate authentication exchange due to an earlier error");
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
return;
}
+ if (wpa_s->dpp_auth_ok_on_ack)
+ wpas_dpp_auth_success(wpa_s, 1);
+
if (!is_broadcast_ether_addr(dst) &&
result != OFFCHANNEL_SEND_ACTION_SUCCESS) {
wpa_printf(MSG_DEBUG,
@@ -300,6 +324,28 @@ static void wpas_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
}
+static void wpas_dpp_set_testing_options(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->dpp_config_obj_override)
+ auth->config_obj_override =
+ os_strdup(wpa_s->dpp_config_obj_override);
+ if (wpa_s->dpp_discovery_override)
+ auth->discovery_override =
+ os_strdup(wpa_s->dpp_discovery_override);
+ if (wpa_s->dpp_groups_override)
+ auth->groups_override =
+ os_strdup(wpa_s->dpp_groups_override);
+ if (wpa_s->dpp_devices_override)
+ auth->devices_override =
+ os_strdup(wpa_s->dpp_devices_override);
+ auth->ignore_netaccesskey_mismatch =
+ wpa_s->dpp_ignore_netaccesskey_mismatch;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
{
const char *pos;
@@ -309,6 +355,10 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
int res;
int configurator = 1;
unsigned int wait_time;
+ struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
+ struct dpp_configurator *conf = NULL;
+
+ wpa_s->dpp_gas_client = 0;
pos = os_strstr(cmd, " peer=");
if (!pos)
@@ -347,7 +397,78 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
else if (os_strncmp(pos, "enrollee", 8) == 0)
configurator = 0;
else
- return -1;
+ goto fail;
+ }
+
+ pos = os_strstr(cmd, " netrole=");
+ if (pos) {
+ pos += 9;
+ wpa_s->dpp_netrole_ap = os_strncmp(pos, "ap", 2) == 0;
+ }
+
+ if (os_strstr(cmd, " conf=sta-")) {
+ conf_sta = os_zalloc(sizeof(struct dpp_configuration));
+ if (!conf_sta)
+ goto fail;
+ /* TODO: Configuration of network parameters from upper layers
+ */
+ os_memcpy(conf_sta->ssid, "test", 4);
+ conf_sta->ssid_len = 4;
+ if (os_strstr(cmd, " conf=sta-psk")) {
+ conf_sta->dpp = 0;
+ conf_sta->passphrase = os_strdup("secret passphrase");
+ if (!conf_sta->passphrase)
+ goto fail;
+ } else if (os_strstr(cmd, " conf=sta-dpp")) {
+ conf_sta->dpp = 1;
+ } else {
+ goto fail;
+ }
+ }
+
+ if (os_strstr(cmd, " conf=ap-")) {
+ conf_ap = os_zalloc(sizeof(struct dpp_configuration));
+ if (!conf_ap)
+ goto fail;
+ /* TODO: Configuration of network parameters from upper layers
+ */
+ os_memcpy(conf_ap->ssid, "test", 4);
+ conf_ap->ssid_len = 4;
+ if (os_strstr(cmd, " conf=ap-psk")) {
+ conf_ap->dpp = 0;
+ conf_ap->passphrase = os_strdup("secret passphrase");
+ if (!conf_ap->passphrase)
+ goto fail;
+ } else if (os_strstr(cmd, " conf=ap-dpp")) {
+ conf_ap->dpp = 1;
+ } 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;
+ }
}
if (wpa_s->dpp_auth) {
@@ -357,7 +478,11 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
}
wpa_s->dpp_auth = dpp_auth_init(wpa_s, peer_bi, own_bi, configurator);
if (!wpa_s->dpp_auth)
- return -1;
+ goto fail;
+ wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
+ wpa_s->dpp_auth->conf_sta = conf_sta;
+ wpa_s->dpp_auth->conf_ap = conf_ap;
+ wpa_s->dpp_auth->conf = conf;
/* TODO: Support iteration over all frequencies and filtering of
* frequencies based on locally enabled channels that allow initiation
@@ -380,6 +505,7 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
os_memcpy(wpa_s->dpp_auth->peer_mac_addr, peer_bi->mac_addr,
ETH_ALEN);
}
+ wpa_s->dpp_auth_ok_on_ack = 0;
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
@@ -394,6 +520,10 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
wpabuf_free(msg);
return res;
+fail:
+ dpp_configuration_free(conf_sta);
+ dpp_configuration_free(conf_ap);
+ return -1;
}
@@ -504,6 +634,7 @@ int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd)
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 (wpa_s->dpp_listen_freq == (unsigned int) freq) {
wpa_printf(MSG_DEBUG, "DPP: Already listening on %u MHz",
freq);
@@ -555,7 +686,7 @@ void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
{
wpas_dpp_listen_work_done(wpa_s);
- if (wpa_s->dpp_auth) {
+ if (wpa_s->dpp_auth && !wpa_s->dpp_gas_client) {
/* Continue listen with a new remain-on-channel */
wpa_printf(MSG_DEBUG,
"DPP: Continue wait on %u MHz for the ongoing DPP provisioning session",
@@ -650,6 +781,8 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
+ 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_qr_mutual,
peer_bi, own_bi, freq, buf,
@@ -658,6 +791,7 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: No response generated");
return;
}
+ wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP,
@@ -674,6 +808,193 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
}
+static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
+{
+ /* TODO: stop wait and start ROC */
+}
+
+
+static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const u8 *pos;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->auth_success) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return;
+ }
+ if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
+ goto fail;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response adv_proto",
+ adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response (GAS response)",
+ resp);
+
+ if (wpabuf_len(adv_proto) != 10 ||
+ !(pos = wpabuf_head(adv_proto)) ||
+ pos[0] != WLAN_EID_ADV_PROTO ||
+ pos[1] != 8 ||
+ pos[3] != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[4] != 5 ||
+ WPA_GET_BE24(&pos[5]) != OUI_WFA ||
+ pos[8] != 0x1a ||
+ pos[9] != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a DPP Advertisement Protocol ID");
+ goto fail;
+ }
+
+ if (dpp_conf_resp_rx(auth, resp) < 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
+ goto fail;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ if (auth->ssid_len)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
+ wpa_ssid_txt(auth->ssid, auth->ssid_len));
+ if (auth->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);
+ }
+ if (auth->c_sign_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(auth->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));
+ if (auth->c_sign_key_expiry)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY
+ "%s %lu", hex,
+ (long unsigned)
+ auth->c_sign_key_expiry);
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY
+ "%s", hex);
+ os_free(hex);
+ }
+ }
+ if (auth->net_access_key) {
+ char *hex;
+ size_t hexlen;
+
+ hexlen = 2 * wpabuf_len(auth->net_access_key) + 1;
+ hex = os_malloc(hexlen);
+ if (hex) {
+ wpa_snprintf_hex(hex, hexlen,
+ wpabuf_head(auth->net_access_key),
+ wpabuf_len(auth->net_access_key));
+ if (auth->net_access_key_expiry)
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_NET_ACCESS_KEY "%s %lu", hex,
+ (long unsigned)
+ auth->net_access_key_expiry);
+ else
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_NET_ACCESS_KEY "%s", hex);
+ os_free(hex);
+ }
+ }
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+
+fail:
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ 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];
+ int res;
+
+ 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");
+ 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) {
+ 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);
+
+ res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq,
+ buf, wpas_dpp_gas_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpabuf_free(buf);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "DPP: GAS query started with dialog token %u", res);
+ }
+}
+
+
+static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
+{
+ wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
+
+ if (wpa_s->dpp_auth->configurator)
+ wpas_dpp_start_gas_server(wpa_s);
+ else
+ wpas_dpp_start_gas_client(wpa_s);
+}
+
+
static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *buf, size_t len)
{
@@ -725,9 +1046,7 @@ static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src,
wpabuf_head(msg), wpabuf_len(msg),
500, wpas_dpp_tx_status, 0);
wpabuf_free(msg);
-
- wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
+ wpa_s->dpp_auth_ok_on_ack = 1;
}
@@ -756,8 +1075,7 @@ static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
- wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=0");
+ wpas_dpp_auth_success(wpa_s, 0);
}
@@ -798,9 +1116,171 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
}
+static struct wpabuf *
+wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
+ size_t query_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ struct wpabuf *resp;
+
+ wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR,
+ MAC2STR(sa));
+ if (!auth || !auth->auth_success ||
+ os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Received Configuration Request (GAS Query Request)",
+ query, query_len);
+ resp = dpp_conf_req_rx(auth, query, query_len);
+ if (!resp)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ return resp;
+}
+
+
+static void
+wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth) {
+ wpabuf_free(resp);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
+ ok);
+ eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
+ offchannel_send_action_done(wpa_s);
+ wpas_dpp_listen_stop(wpa_s);
+ if (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(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ wpabuf_free(resp);
+}
+
+
+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 *expiry = NULL, *curve = NULL;
+ char *key = NULL;
+ u8 *privkey = NULL;
+ size_t privkey_len = 0;
+ int ret = -1;
+ struct dpp_configurator *conf = NULL;
+
+ expiry = get_param(cmd, " expiry=");
+ 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;
+
+ if (expiry) {
+ long int val;
+
+ val = strtol(expiry, NULL, 0);
+ if (val <= 0)
+ goto fail;
+ conf->csign_expiry = val;
+ }
+
+ 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);
+ os_free(expiry);
+ 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_init(struct wpa_supplicant *wpa_s)
{
+ u8 adv_proto_id[7];
+
+ adv_proto_id[0] = WLAN_EID_VENDOR_SPECIFIC;
+ adv_proto_id[1] = 5;
+ WPA_PUT_BE24(&adv_proto_id[2], OUI_WFA);
+ adv_proto_id[5] = DPP_OUI_TYPE;
+ adv_proto_id[6] = 0x01;
+
+ if (gas_server_register(wpa_s->gas_server, adv_proto_id,
+ 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;
}
@@ -808,12 +1288,24 @@ int wpas_dpp_init(struct wpa_supplicant *wpa_s)
void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ os_free(wpa_s->dpp_config_obj_override);
+ wpa_s->dpp_config_obj_override = NULL;
+ os_free(wpa_s->dpp_discovery_override);
+ wpa_s->dpp_discovery_override = NULL;
+ os_free(wpa_s->dpp_groups_override);
+ wpa_s->dpp_groups_override = NULL;
+ os_free(wpa_s->dpp_devices_override);
+ wpa_s->dpp_devices_override = NULL;
+ wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->dpp_init_done)
return;
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
dpp_bootstrap_del(wpa_s, 0);
+ dpp_configurator_del(wpa_s, 0);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
}
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index fc1e878..403f436 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -23,6 +23,8 @@ void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *buf, size_t len, unsigned int freq);
+int wpas_dpp_configurator_add(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_configurator_remove(struct wpa_supplicant *wpa_s, const char *id);
int wpas_dpp_init(struct wpa_supplicant *wpa_s);
void wpas_dpp_deinit(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 0bfd3b9..648ffdc 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -29,6 +29,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/dpp.h"
+#include "common/gas_server.h"
#include "crypto/random.h"
#include "blacklist.h"
#include "wpas_glue.h"
@@ -3530,6 +3531,15 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
return;
#endif /* CONFIG_GAS */
+#ifdef CONFIG_GAS_SERVER
+ if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC ||
+ mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) &&
+ gas_server_rx(wpa_s->gas_server, mgmt->da, mgmt->sa, mgmt->bssid,
+ mgmt->u.action.category,
+ payload, plen, freq) == 0)
+ return;
+#endif /* CONFIG_GAS_SERVER */
+
#ifdef CONFIG_TDLS
if (category == WLAN_ACTION_PUBLIC && plen >= 4 &&
payload[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f0bf35f..0a107b0 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -38,6 +38,7 @@
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
+#include "common/gas_server.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
#include "blacklist.h"
@@ -547,6 +548,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
radio_remove_works(wpa_s, "gas-query", 0);
gas_query_deinit(wpa_s->gas);
wpa_s->gas = NULL;
+ gas_server_deinit(wpa_s->gas_server);
+ wpa_s->gas_server = NULL;
free_hw_features(wpa_s);
@@ -4939,6 +4942,41 @@ next_driver:
}
+#ifdef CONFIG_GAS_SERVER
+
+static void wpas_gas_server_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)
+{
+ wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
+ " result=%s",
+ freq, MAC2STR(dst),
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED"));
+ gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
+ result == OFFCHANNEL_SEND_ACTION_SUCCESS);
+}
+
+
+static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
+ struct wpabuf *buf, unsigned int wait_time)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ if (wait_time > wpa_s->max_remain_on_chan)
+ wait_time = wpa_s->max_remain_on_chan;
+
+ offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
+ wpabuf_head(buf), wpabuf_len(buf),
+ wait_time, wpas_gas_server_tx_status, 0);
+}
+
+#endif /* CONFIG_GAS_SERVER */
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
@@ -5183,6 +5221,14 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (wpas_wps_init(wpa_s))
return -1;
+#ifdef CONFIG_GAS_SERVER
+ wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
+ if (!wpa_s->gas_server) {
+ wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
+ return -1;
+ }
+#endif /* CONFIG_GAS_SERVER */
+
#ifdef CONFIG_DPP
if (wpas_dpp_init(wpa_s) < 0)
return -1;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 53c5e79..20cc717 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -962,6 +962,7 @@ struct wpa_supplicant {
int best_overall_freq;
struct gas_query *gas;
+ struct gas_server *gas_server;
#ifdef CONFIG_INTERWORKING
unsigned int fetch_anqp_in_progress:1;
@@ -1159,6 +1160,7 @@ struct wpa_supplicant {
#ifdef CONFIG_DPP
struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
+ struct dl_list dpp_configurator; /* struct dpp_configurator */
int dpp_init_done;
struct dpp_authentication *dpp_auth;
struct wpa_radio_work *dpp_listen_work;
@@ -1166,6 +1168,16 @@ struct wpa_supplicant {
unsigned int dpp_listen_freq;
u8 dpp_allowed_roles;
int dpp_qr_mutual;
+ int dpp_netrole_ap;
+ int dpp_auth_ok_on_ack;
+ int dpp_gas_client;
+#ifdef CONFIG_TESTING_OPTIONS
+ char *dpp_config_obj_override;
+ char *dpp_discovery_override;
+ char *dpp_groups_override;
+ char *dpp_devices_override;
+ unsigned int dpp_ignore_netaccesskey_mismatch:1;
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
};