aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/Android.mk1
-rw-r--r--wpa_supplicant/Makefile1
-rw-r--r--wpa_supplicant/ap.c3
-rw-r--r--wpa_supplicant/config.c38
-rw-r--r--wpa_supplicant/config.h1
-rw-r--r--wpa_supplicant/config_file.c1
-rw-r--r--wpa_supplicant/config_ssid.h16
-rw-r--r--wpa_supplicant/ctrl_iface.c189
-rw-r--r--wpa_supplicant/dpp_supplicant.c422
-rw-r--r--wpa_supplicant/dpp_supplicant.h3
-rw-r--r--wpa_supplicant/driver_i.h12
-rw-r--r--wpa_supplicant/events.c816
-rwxr-xr-xwpa_supplicant/examples/dpp-nfc.py657
-rw-r--r--wpa_supplicant/gas_query.c16
-rw-r--r--wpa_supplicant/interworking.c25
-rw-r--r--wpa_supplicant/interworking.h2
-rw-r--r--wpa_supplicant/mesh_mpm.c2
-rw-r--r--wpa_supplicant/op_classes.c6
-rw-r--r--wpa_supplicant/preauth_test.c3
-rw-r--r--wpa_supplicant/robust_av.c157
-rw-r--r--wpa_supplicant/scan.c134
-rw-r--r--wpa_supplicant/sme.c66
-rw-r--r--wpa_supplicant/wnm_sta.c9
-rw-r--r--wpa_supplicant/wpa_cli.c74
-rw-r--r--wpa_supplicant/wpa_supplicant.c75
-rw-r--r--wpa_supplicant/wpa_supplicant.conf52
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h32
-rw-r--r--wpa_supplicant/wpas_glue.c37
28 files changed, 2203 insertions, 647 deletions
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 0f24d7b..ed7e358 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -98,6 +98,7 @@ OBJS += src/utils/crc32.c
OBJS += wmm_ac.c
OBJS += op_classes.c
OBJS += rrm.c
+OBJS += robust_av.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
OBJS_p += src/utils/wpa_debug.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 09ac7a4..a01a329 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -107,6 +107,7 @@ OBJS += ../src/utils/ip_addr.o
OBJS += ../src/utils/crc32.o
OBJS += op_classes.o
OBJS += rrm.o
+OBJS += robust_av.o
OBJS_p = wpa_passphrase.o
OBJS_p += ../src/utils/common.o
OBJS_p += ../src/utils/wpa_debug.o
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6241682..2accf92 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -858,6 +858,9 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
wpa_s->conf->wmm_ac_params,
sizeof(wpa_s->conf->wmm_ac_params));
+ os_memcpy(wpa_s->ap_iface->conf->tx_queue, wpa_s->conf->tx_queue,
+ sizeof(wpa_s->conf->tx_queue));
+
if (params.uapsd > 0) {
conf->bss[0]->wmm_enabled = 1;
conf->bss[0]->wmm_uapsd = 1;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 49b25f1..0b4a66a 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2582,6 +2582,7 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
{ INT_RANGE(beacon_prot, 0, 1) },
{ INT_RANGE(transition_disable, 0, 255) },
+ { INT_RANGE(sae_pk, 0, 2) },
};
#undef OFFSET
@@ -4254,6 +4255,8 @@ int wpa_config_remove_blob(struct wpa_config *config, const char *name)
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param)
{
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
struct wpa_config *config;
const int aCWmin = 4, aCWmax = 10;
const struct hostapd_wmm_ac_params ac_bk =
@@ -4264,6 +4267,17 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+ const struct hostapd_tx_queue_params txq_bk =
+ { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+ const struct hostapd_tx_queue_params txq_be =
+ { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0 };
+ const struct hostapd_tx_queue_params txq_vi =
+ { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30 };
+ const struct hostapd_tx_queue_params txq_vo =
+ { 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+ (ecw2cw(aCWmin) + 1) / 2 - 1, 15 };
+
+#undef ecw2cw
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -4293,6 +4307,10 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->wmm_ac_params[1] = ac_bk;
config->wmm_ac_params[2] = ac_vi;
config->wmm_ac_params[3] = ac_vo;
+ config->tx_queue[0] = txq_vo;
+ config->tx_queue[1] = txq_vi;
+ config->tx_queue[2] = txq_be;
+ config->tx_queue[3] = txq_bk;
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
@@ -5164,6 +5182,26 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
}
if (i == NUM_GLOBAL_FIELDS) {
#ifdef CONFIG_AP
+ if (os_strncmp(pos, "tx_queue_", 9) == 0) {
+ char *tmp = os_strchr(pos, '=');
+
+ if (!tmp) {
+ if (line < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid line %s",
+ line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_tx_queue(config->tx_queue, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid TX queue item",
+ line);
+ return -1;
+ }
+ }
+
if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
char *tmp = os_strchr(pos, '=');
if (tmp == NULL) {
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 2d4cb1b..a385da5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1058,6 +1058,7 @@ struct wpa_config {
int p2p_go_max_inactivity;
struct hostapd_wmm_ac_params wmm_ac_params[4];
+ struct hostapd_tx_queue_params tx_queue[4];
/**
* auto_interworking - Whether to use network selection automatically
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index a69c4cc..1ca2548 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -937,6 +937,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(ft_eap_pmksa_caching);
INT(beacon_prot);
INT(transition_disable);
+ INT(sae_pk);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 1e2c322..2c08c02 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -62,6 +62,12 @@ enum wpas_mode {
WPAS_MODE_MESH = 5,
};
+enum sae_pk_mode {
+ SAE_PK_MODE_AUTOMATIC = 0,
+ SAE_PK_MODE_ONLY = 1,
+ SAE_PK_MODE_DISABLED = 2,
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -1121,6 +1127,16 @@ struct wpa_ssid {
* OWE)
*/
u8 transition_disable;
+
+ /**
+ * sae_pk - SAE-PK mode
+ * 0 = automatic SAE/SAE-PK selection based on password; enable
+ * transition mode (allow SAE authentication without SAE-PK)
+ * 1 = SAE-PK only (disable transition mode; allow SAE authentication
+ * only with SAE-PK)
+ * 2 = disable SAE-PK (allow SAE authentication only without SAE-PK)
+ */
+ enum sae_pk_mode sae_pk;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e727dc5..5048ee8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -757,6 +757,20 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->oci_freq_override_saquery_req = atoi(value);
} else if (os_strcasecmp(cmd, "oci_freq_override_saquery_resp") == 0) {
wpa_s->oci_freq_override_saquery_resp = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_eapol_g2") == 0) {
+ wpa_s->oci_freq_override_eapol_g2 = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_ft_assoc") == 0) {
+ wpa_s->oci_freq_override_ft_assoc = atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_fils_assoc") == 0) {
+ wpa_s->oci_freq_override_fils_assoc = atoi(value);
+ } else if (os_strcasecmp(cmd, "oci_freq_override_wnm_sleep") == 0) {
+ wpa_s->oci_freq_override_wnm_sleep = atoi(value);
} else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) {
wpabuf_free(wpa_s->rsne_override_eapol);
if (os_strcmp(value, "NULL") == 0)
@@ -2283,8 +2297,12 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
!wpa_s->ap_iface &&
#endif /* CONFIG_AP */
wpa_s->sme.sae.state == SAE_ACCEPTED) {
- ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
- wpa_s->sme.sae.group);
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n"
+ "sae_h2e=%d\n"
+ "sae_pk=%d\n",
+ wpa_s->sme.sae.group,
+ wpa_s->sme.sae.h2e,
+ wpa_s->sme.sae.pk);
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -4217,6 +4235,27 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK) {
+ ret = os_snprintf(pos, end - pos, " WAPI-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_TPK_HANDSHAKE) {
+ ret = os_snprintf(pos, end - pos, " TPK-HANDSHAKE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_CCKM) {
+ ret = os_snprintf(pos, end - pos, " CCKM");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_SUITEB
if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
@@ -4284,6 +4323,28 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_SAE
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, " FT-SAE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_SHA384
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384) {
+ ret = os_snprintf(pos, end - pos, " FT-EAP-SHA384");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
@@ -4293,6 +4354,29 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict,
pos += ret;
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SHA256
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256) {
+ ret = os_snprintf(pos, end - pos, " WPA-PSK-SHA256");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_HS20
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OSEN) {
+ ret = os_snprintf(pos, end - pos, " OSEN");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
return pos - buf;
}
@@ -7382,7 +7466,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst,
static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
{
u8 dst_addr[ETH_ALEN];
- int used;
+ int used, freq = 0;
char *pos;
#define MAX_ANQP_INFO_ID 100
u16 id[MAX_ANQP_INFO_ID];
@@ -7396,6 +7480,15 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
pos = dst + used;
if (*pos == ' ')
pos++;
+
+ if (os_strncmp(pos, "freq=", 5) == 0) {
+ freq = atoi(pos + 5);
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ }
+
while (num_id < MAX_ANQP_INFO_ID) {
if (os_strncmp(pos, "hs20:", 5) == 0) {
#ifdef CONFIG_HS20
@@ -7430,7 +7523,7 @@ static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
if (num_id == 0 && !subtypes && !mbo_subtypes)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ return anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes,
mbo_subtypes);
}
@@ -8368,6 +8461,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->oci_freq_override_eapol = 0;
wpa_s->oci_freq_override_saquery_req = 0;
wpa_s->oci_freq_override_saquery_resp = 0;
+ wpa_s->oci_freq_override_eapol_g2 = 0;
+ wpa_s->oci_freq_override_ft_assoc = 0;
+ wpa_s->oci_freq_override_fils_assoc = 0;
+ wpa_s->oci_freq_override_wnm_sleep = 0;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8386,6 +8483,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->next_scan_bssid_wildcard_ssid = 0;
os_free(wpa_s->select_network_scan_freqs);
wpa_s->select_network_scan_freqs = NULL;
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
wpa_bss_flush(wpa_s);
if (!dl_list_empty(&wpa_s->bss)) {
@@ -8411,6 +8509,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_supplicant_update_channel_list(wpa_s, NULL);
free_bss_tmp_disallowed(wpa_s);
+
+ os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
}
@@ -10245,6 +10345,76 @@ static int wpas_ctrl_cmd_debug_level(const char *cmd)
}
+static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ size_t frame_classifier_len;
+ const char *pos, *end;
+ struct robust_av_data *robust_av = &wpa_s->robust_av;
+ int val;
+
+ /*
+ * format:
+ * <add|remove|change> [up_bitmap=<hex byte>] [up_limit=<integer>]
+ * [stream_timeout=<in TUs>] [frame_classifier=<hex bytes>]
+ */
+ os_memset(robust_av, 0, sizeof(struct robust_av_data));
+ if (os_strncmp(cmd, "add ", 4) == 0) {
+ robust_av->request_type = SCS_REQ_ADD;
+ } else if (os_strcmp(cmd, "remove") == 0) {
+ robust_av->request_type = SCS_REQ_REMOVE;
+ robust_av->valid_config = false;
+ return wpas_send_mscs_req(wpa_s);
+ } else if (os_strncmp(cmd, "change ", 7) == 0) {
+ robust_av->request_type = SCS_REQ_CHANGE;
+ } else {
+ return -1;
+ }
+
+ pos = os_strstr(cmd, "up_bitmap=");
+ if (!pos)
+ return -1;
+
+ val = hex2byte(pos + 10);
+ if (val < 0)
+ return -1;
+ robust_av->up_bitmap = val;
+
+ pos = os_strstr(cmd, "up_limit=");
+ if (!pos)
+ return -1;
+
+ robust_av->up_limit = atoi(pos + 9);
+
+ pos = os_strstr(cmd, "stream_timeout=");
+ if (!pos)
+ return -1;
+
+ robust_av->stream_timeout = atoi(pos + 15);
+ if (robust_av->stream_timeout == 0)
+ return -1;
+
+ pos = os_strstr(cmd, "frame_classifier=");
+ if (!pos)
+ return -1;
+
+ pos += 17;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ frame_classifier_len = (end - pos) / 2;
+ if (frame_classifier_len > sizeof(robust_av->frame_classifier) ||
+ hexstr2bin(pos, robust_av->frame_classifier, frame_classifier_len))
+ return -1;
+
+ robust_av->frame_classifier_len = frame_classifier_len;
+ robust_av->valid_config = true;
+
+ return wpas_send_mscs_req(wpa_s);
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -11129,13 +11299,16 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
wpas_dpp_chirp_stop(wpa_s);
} else if (os_strncmp(buf, "DPP_RECONFIG ", 13) == 0) {
- struct wpa_ssid *ssid;
-
- ssid = wpa_config_get_network(wpa_s->conf, atoi(buf + 13));
- if (!ssid || wpas_dpp_reconfig(wpa_s, ssid) < 0)
+ if (wpas_dpp_reconfig(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_CA_SET ", 11) == 0) {
+ if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
reply_len = -1;
#endif /* CONFIG_DPP2 */
#endif /* CONFIG_DPP */
+ } else if (os_strncmp(buf, "MSCS ", 5) == 0) {
+ if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index a41b3f5..fdb9cbd 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -12,6 +12,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/ip_addr.h"
+#include "utils/base64.h"
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
@@ -48,6 +49,9 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_DPP2
static void wpas_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s);
+static int wpas_dpp_process_conf_obj(void *ctx,
+ struct dpp_authentication *auth);
#endif /* CONFIG_DPP2 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -88,6 +92,10 @@ int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd)
500, wpas_dpp_tx_status, 0);
}
+#ifdef CONFIG_DPP2
+ dpp_controller_new_qr_code(wpa_s->dpp, bi);
+#endif /* CONFIG_DPP2 */
+
return bi->id;
}
@@ -829,7 +837,9 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
#ifdef CONFIG_DPP2
if (tcp)
- return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port);
+ return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
+ wpa_s->conf->dpp_name, DPP_NETROLE_STA,
+ wpa_s, wpa_s, wpas_dpp_process_conf_obj);
#endif /* CONFIG_DPP2 */
wpa_s->dpp_auth = auth;
@@ -1217,6 +1227,102 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_DPP2
+ if (conf->akm == DPP_AKM_DOT1X) {
+ int i;
+ char name[100], blobname[128];
+ struct wpa_config_blob *blob;
+
+ ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SHA256;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+
+ if (conf->cacert) {
+ /* caCert is DER-encoded X.509v3 certificate for the
+ * server certificate if that is different from the
+ * trust root included in certBag. */
+ /* TODO: ssid->eap.cert.ca_cert */
+ }
+
+ if (conf->certs) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-certs-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(conf->certs);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(conf->certs),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added certificate blob %s",
+ name);
+ ssid->eap.cert.client_cert = os_strdup(blobname);
+ if (!ssid->eap.cert.client_cert)
+ goto fail;
+
+ /* TODO: ssid->eap.identity from own certificate */
+ if (wpa_config_set(ssid, "identity", "\"dpp-ent\"",
+ 0) < 0)
+ goto fail;
+ }
+
+ if (auth->priv_key) {
+ for (i = 0; ; i++) {
+ os_snprintf(name, sizeof(name), "dpp-key-%d",
+ i);
+ if (!wpa_config_get_blob(wpa_s->conf, name))
+ break;
+ }
+
+ blob = os_zalloc(sizeof(*blob));
+ if (!blob)
+ goto fail;
+ blob->len = wpabuf_len(auth->priv_key);
+ blob->name = os_strdup(name);
+ blob->data = os_malloc(blob->len);
+ if (!blob->name || !blob->data) {
+ wpa_config_free_blob(blob);
+ goto fail;
+ }
+ os_memcpy(blob->data, wpabuf_head(auth->priv_key),
+ blob->len);
+ os_snprintf(blobname, sizeof(blobname), "blob://%s",
+ name);
+ wpa_config_set_blob(wpa_s->conf, blob);
+ wpa_printf(MSG_DEBUG, "DPP: Added private key blob %s",
+ name);
+ ssid->eap.cert.private_key = os_strdup(blobname);
+ if (!ssid->eap.cert.private_key)
+ goto fail;
+ }
+
+ if (conf->server_name) {
+ ssid->eap.cert.domain_suffix_match =
+ os_strdup(conf->server_name);
+ if (!ssid->eap.cert.domain_suffix_match)
+ goto fail;
+ }
+
+ /* TODO: Use entCreds::eapMethods */
+ if (wpa_config_set(ssid, "eap", "TLS", 0) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_DPP2 */
+
os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
wpa_s->dpp_last_ssid_len = conf->ssid_len;
@@ -1345,6 +1451,32 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
}
+#ifdef CONFIG_DPP2
+ if (conf->certbag) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->certbag),
+ wpabuf_len(conf->certbag), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CERTBAG "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->cacert) {
+ char *b64;
+
+ b64 = base64_encode_no_lf(wpabuf_head(conf->cacert),
+ wpabuf_len(conf->cacert), NULL);
+ if (b64)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CACERT "%s", b64);
+ os_free(b64);
+ }
+
+ if (conf->server_name)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_SERVER_NAME "%s",
+ conf->server_name);
+#endif /* CONFIG_DPP2 */
+
return wpas_dpp_process_config(wpa_s, auth, conf);
}
@@ -1360,6 +1492,7 @@ static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
+ wpa_s->dpp_conf_backup_received = true;
while (key) {
res = dpp_configurator_from_backup(wpa_s->dpp, key);
@@ -1375,6 +1508,31 @@ static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_DPP2
+static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->csrattrs)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build CSR");
+ wpabuf_free(auth->csr);
+ /* TODO: Additional information needed for CSR based on csrAttrs */
+ auth->csr = dpp_build_csr(auth, wpa_s->conf->dpp_name ?
+ wpa_s->conf->dpp_name : "Test");
+ if (!auth->csr) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
+
+ wpas_dpp_start_gas_client(wpa_s);
+}
+#endif /* CONFIG_DPP2 */
+
+
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,
@@ -1419,11 +1577,20 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- if (dpp_conf_resp_rx(auth, resp) < 0) {
+ res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP2
+ if (res == -2) {
+ wpa_printf(MSG_DEBUG, "DPP: CSR needed");
+ eloop_register_timeout(0, 0, wpas_dpp_build_csr, wpa_s, NULL);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
}
+ wpa_s->dpp_conf_backup_received = false;
for (i = 0; i < auth->num_conf_obj; i++) {
res = wpas_dpp_handle_config_obj(wpa_s, auth,
&auth->conf_obj[i]);
@@ -1467,6 +1634,9 @@ fail:
wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
+ if (wpa_s->conf->dpp_config_processing < 2 ||
+ wpa_s->dpp_conf_backup_received)
+ auth->remove_on_tx_status = 1;
return;
}
fail2:
@@ -1859,11 +2029,12 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
- const u8 *csign_hash;
- u16 csign_hash_len;
+ const u8 *csign_hash, *fcgroup, *a_nonce, *e_id;
+ u16 csign_hash_len, fcgroup_len, a_nonce_len, e_id_len;
struct dpp_configurator *conf;
struct dpp_authentication *auth;
unsigned int wait_time, max_wait_time;
+ u16 group;
if (!wpa_s->dpp)
return;
@@ -1893,7 +2064,21 @@ wpas_dpp_rx_reconfig_announcement(struct wpa_supplicant *wpa_s, const u8 *src,
return;
}
- auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq);
+ fcgroup = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Missing or invalid required Finite Cyclic Group attribute");
+ return;
+ }
+ group = WPA_GET_LE16(fcgroup);
+ wpa_printf(MSG_DEBUG, "DPP: Enrollee finite cyclic group: %u", group);
+
+ a_nonce = dpp_get_attr(buf, len, DPP_ATTR_A_NONCE, &a_nonce_len);
+ e_id = dpp_get_attr(buf, len, DPP_ATTR_E_PRIME_ID, &e_id_len);
+
+ auth = dpp_reconfig_init(wpa_s->dpp, wpa_s, conf, freq, group,
+ a_nonce, a_nonce_len, e_id, e_id_len);
if (!auth)
return;
wpas_dpp_set_testing_options(wpa_s, auth);
@@ -1943,17 +2128,29 @@ wpas_dpp_rx_reconfig_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
wpa_printf(MSG_DEBUG, "DPP: Reconfig Authentication Request from "
MACSTR, MAC2STR(src));
- if (!wpa_s->dpp || wpa_s->dpp_auth ||
- !wpa_s->dpp_reconfig_announcement || !wpa_s->dpp_reconfig_ssid)
+ if (!wpa_s->dpp)
+ return;
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - pending authentication exchange in progress");
return;
+ }
+ if (!wpa_s->dpp_reconfig_ssid) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - not requested");
+ return;
+ }
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid == wpa_s->dpp_reconfig_ssid &&
ssid->id == wpa_s->dpp_reconfig_ssid_id)
break;
}
if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready for reconfiguration - no matching network profile with Connector found");
return;
+ }
auth = dpp_reconfig_auth_req_rx(wpa_s->dpp, wpa_s, ssid->dpp_connector,
ssid->dpp_netaccesskey,
@@ -2647,8 +2844,8 @@ 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)
+wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa,
+ const u8 *query, size_t query_len, u16 *comeback_delay)
{
struct wpa_supplicant *wpa_s = ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
@@ -2679,6 +2876,16 @@ wpas_dpp_gas_req_handler(void *ctx, const u8 *sa, const u8 *query,
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_REQ_RX "src=" MACSTR,
MAC2STR(sa));
resp = dpp_conf_req_rx(auth, query, query_len);
+
+#ifdef CONFIG_DPP2
+ if (!resp && auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready");
+ auth->cert_resp_ctx = resp_ctx;
+ *comeback_delay = 500;
+ return NULL;
+ }
+#endif /* CONFIG_DPP2 */
+
if (!resp)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
auth->conf_resp = resp;
@@ -2704,6 +2911,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
return;
}
+#ifdef CONFIG_DPP2
+ if (auth->waiting_csr && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for CSR");
+ wpabuf_free(resp);
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
@@ -3084,7 +3299,6 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_TESTING_OPTIONS */
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);
@@ -3096,9 +3310,12 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout,
wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL);
dpp_pfs_free(wpa_s->dpp_pfs);
wpa_s->dpp_pfs = NULL;
wpas_dpp_chirp_stop(wpa_s);
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = NULL;
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
@@ -3107,6 +3324,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *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;
+ dpp_global_clear(wpa_s->dpp);
}
@@ -3139,6 +3357,8 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
else
return -1;
}
+
+ config.qr_mutual = os_strstr(cmd, " qr=mutual") != NULL;
}
config.configurator_params = wpa_s->dpp_configurator_params;
return dpp_controller_start(wpa_s->dpp, &config);
@@ -3181,13 +3401,26 @@ static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
{
- struct wpabuf *msg;
+ struct wpabuf *msg, *announce = NULL;
int type;
msg = wpa_s->dpp_presence_announcement;
type = DPP_PA_PRESENCE_ANNOUNCEMENT;
if (!msg) {
- msg = wpa_s->dpp_reconfig_announcement;
+ struct wpa_ssid *ssid = wpa_s->dpp_reconfig_ssid;
+
+ if (ssid && wpa_s->dpp_reconfig_id &&
+ wpa_config_get_network(wpa_s->conf,
+ wpa_s->dpp_reconfig_ssid_id) ==
+ ssid) {
+ announce = dpp_build_reconfig_announcement(
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ wpa_s->dpp_reconfig_id);
+ msg = announce;
+ }
if (!msg)
return;
type = DPP_PA_RECONFIG_ANNOUNCEMENT;
@@ -3201,6 +3434,8 @@ static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
wpabuf_head(msg), wpabuf_len(msg),
2000, wpas_dpp_chirp_tx_status, 0) < 0)
wpas_dpp_chirp_stop(wpa_s);
+
+ wpabuf_free(announce);
}
@@ -3213,7 +3448,7 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
int c;
struct wpa_bss *bss;
- if (!bi && !wpa_s->dpp_reconfig_announcement)
+ if (!bi && !wpa_s->dpp_reconfig_ssid)
return;
wpa_s->dpp_chirp_scan_done = 1;
@@ -3401,15 +3636,13 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
{
if (wpa_s->dpp_presence_announcement ||
- wpa_s->dpp_reconfig_announcement) {
+ wpa_s->dpp_reconfig_ssid) {
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;
- wpabuf_free(wpa_s->dpp_reconfig_announcement);
- wpa_s->dpp_reconfig_announcement = NULL;
if (wpa_s->dpp_chirp_listen)
wpas_dpp_listen_stop(wpa_s);
wpa_s->dpp_chirp_listen = 0;
@@ -3425,23 +3658,53 @@ void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
}
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd)
{
- if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)
+ struct wpa_ssid *ssid;
+ int iter = 1;
+ const char *pos;
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not a valid network profile for reconfiguration");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " iter=");
+ if (pos) {
+ iter = atoi(pos + 6);
+ if (iter <= 0)
+ return -1;
+ }
+
+ if (wpa_s->dpp_auth) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Not ready to start reconfiguration - pending authentication exchange in progress");
return -1;
+ }
+ dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
+ wpa_s->dpp_reconfig_id = dpp_gen_reconfig_id(ssid->dpp_csign,
+ ssid->dpp_csign_len);
+ if (!wpa_s->dpp_reconfig_id) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to generate E-id for reconfiguration");
+ return -1;
+ }
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_printf(MSG_DEBUG, "DPP: Disconnect for reconfiguration");
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
wpas_dpp_chirp_stop(wpa_s);
wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
wpa_s->dpp_qr_mutual = 0;
- wpa_s->dpp_reconfig_announcement =
- dpp_build_reconfig_announcement(ssid->dpp_csign,
- ssid->dpp_csign_len);
- if (!wpa_s->dpp_reconfig_announcement)
- return -1;
wpa_s->dpp_reconfig_ssid = ssid;
wpa_s->dpp_reconfig_ssid_id = ssid->id;
- wpa_s->dpp_chirp_iter = 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 = 0;
@@ -3449,4 +3712,111 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
}
+
+static int wpas_dpp_build_conf_resp(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth, bool tcp)
+{
+ struct wpabuf *resp;
+
+ resp = dpp_build_conf_resp(auth, auth->e_nonce, auth->curve->nonce_len,
+ auth->e_netrole, true);
+ if (!resp)
+ return -1;
+
+ if (tcp) {
+ auth->conf_resp_tcp = resp;
+ return 0;
+ }
+
+ if (gas_server_set_resp(wpa_s->gas_server, auth->cert_resp_ctx,
+ resp) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Could not find pending GAS response");
+ wpabuf_free(resp);
+ return -1;
+ }
+ auth->conf_resp = resp;
+ return 0;
+}
+
+
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int peer = -1;
+ const char *pos, *value;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+ u8 *bin;
+ size_t bin_len;
+ struct wpabuf *buf;
+ bool tcp = false;
+
+ pos = os_strstr(cmd, " peer=");
+ if (pos) {
+ peer = atoi(pos + 6);
+ if (!auth || !auth->waiting_cert ||
+ (auth->peer_bi &&
+ (unsigned int) peer != auth->peer_bi->id)) {
+ auth = dpp_controller_get_auth(wpa_s->dpp, peer);
+ tcp = true;
+ }
+ }
+
+ if (!auth || !auth->waiting_cert) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No authentication exchange waiting for certificate information");
+ return -1;
+ }
+
+ if (peer >= 0 &&
+ (!auth->peer_bi ||
+ (unsigned int) peer != auth->peer_bi->id) &&
+ (!auth->tmp_peer_bi ||
+ (unsigned int) peer != auth->tmp_peer_bi->id)) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer mismatch");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " value=");
+ if (!pos)
+ return -1;
+ value = pos + 7;
+
+ pos = os_strstr(cmd, " name=");
+ if (!pos)
+ return -1;
+ pos += 6;
+
+ if (os_strncmp(pos, "status ", 7) == 0) {
+ auth->force_conf_resp_status = atoi(value);
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ if (os_strncmp(pos, "trustedEapServerName ", 21) == 0) {
+ os_free(auth->trusted_eap_server_name);
+ auth->trusted_eap_server_name = os_strdup(value);
+ return auth->trusted_eap_server_name ? 0 : -1;
+ }
+
+ bin = base64_decode(value, os_strlen(value), &bin_len);
+ if (!bin)
+ return -1;
+ buf = wpabuf_alloc_copy(bin, bin_len);
+ os_free(bin);
+
+ if (os_strncmp(pos, "caCert ", 7) == 0) {
+ wpabuf_free(auth->cacert);
+ auth->cacert = buf;
+ return 0;
+ }
+
+ if (os_strncmp(pos, "certBag ", 8) == 0) {
+ wpabuf_free(auth->certbag);
+ auth->certbag = buf;
+ return wpas_dpp_build_conf_resp(wpa_s, auth, tcp);
+ }
+
+ wpabuf_free(buf);
+ return -1;
+}
+
#endif /* CONFIG_DPP2 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 2dc86e0..b0d5fcf 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -39,6 +39,7 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
enum dpp_status_error result);
int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
-int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 54ae03b..ba8cc55 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1069,14 +1069,14 @@ static inline int wpa_drv_ignore_assoc_disallow(struct wpa_supplicant *wpa_s,
return wpa_s->driver->ignore_assoc_disallow(wpa_s->drv_priv, val);
}
-static inline int wpa_drv_set_bssid_blacklist(struct wpa_supplicant *wpa_s,
- unsigned int num_bssid,
- const u8 *bssids)
+static inline int wpa_drv_set_bssid_tmp_disallow(struct wpa_supplicant *wpa_s,
+ unsigned int num_bssid,
+ const u8 *bssids)
{
- if (!wpa_s->driver->set_bssid_blacklist)
+ if (!wpa_s->driver->set_bssid_tmp_disallow)
return -1;
- return wpa_s->driver->set_bssid_blacklist(wpa_s->drv_priv, num_bssid,
- bssids);
+ return wpa_s->driver->set_bssid_tmp_disallow(wpa_s->drv_priv, num_bssid,
+ bssids);
}
static inline int wpa_drv_update_connect_params(
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f0f9189..80b803f 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1083,32 +1083,407 @@ static int disabled_freq(struct wpa_supplicant *wpa_s, int freq)
}
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, struct wpa_blacklist *e,
+ bool debug_print);
+
+
+#ifdef CONFIG_SAE_PK
+static bool sae_pk_acceptable_bss_with_pk(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *orig_bss,
+ struct wpa_ssid *ssid,
+ const u8 *match_ssid,
+ size_t match_ssid_len)
+{
+ struct wpa_bss *bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ struct wpa_blacklist *e;
+ const u8 *ie;
+ u8 rsnxe_capa = 0;
+
+ if (bss == orig_bss)
+ continue;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+ if (!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)))
+ continue;
+
+ /* TODO: Could be more thorough in checking what kind of
+ * signal strength or throughput estimate would be acceptable
+ * compared to the originally selected BSS. */
+ if (bss->est_throughput < 2000)
+ return false;
+
+ e = wpa_blacklist_get(wpa_s, bss->bssid);
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, e, 0))
+ return true;
+ }
+
+ return false;
+}
+#endif /* CONFIG_SAE_PK */
+
+
+static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ const u8 *match_ssid, size_t match_ssid_len,
+ struct wpa_bss *bss, struct wpa_blacklist *e,
+ bool debug_print)
+{
+ int res;
+ bool wpa, check_ssid, osen, rsn_osen = false;
+ struct wpa_ie_data data;
+#ifdef CONFIG_MBO
+ const u8 *assoc_disallow;
+#endif /* CONFIG_MBO */
+#ifdef CONFIG_SAE
+ u8 rsnxe_capa = 0;
+#endif /* CONFIG_SAE */
+ const u8 *ie;
+
+ ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ wpa = ie && ie[1];
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ wpa |= ie && ie[1];
+ if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
+ (data.key_mgmt & WPA_KEY_MGMT_OSEN))
+ rsn_osen = true;
+ ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
+ osen = ie != NULL;
+
+#ifdef CONFIG_SAE
+ ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (ie && ie[1] >= 1)
+ rsnxe_capa = ie[2];
+#endif /* CONFIG_SAE */
+
+ check_ssid = wpa || ssid->ssid_len > 0;
+
+ if (wpas_network_disabled(wpa_s, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ return false;
+ }
+
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
+ return false;
+ }
+
+#ifdef CONFIG_WPS
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (WPS)");
+ return false;
+ }
+
+ if (wpa && ssid->ssid_len == 0 &&
+ wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+ check_ssid = false;
+
+ if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+ /* Only allow wildcard SSID match if an AP advertises active
+ * WPS operation that matches our mode. */
+ check_ssid = ssid->ssid_len > 0 ||
+ !wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss);
+ }
+#endif /* CONFIG_WPS */
+
+ if (ssid->bssid_set && ssid->ssid_len == 0 &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+ check_ssid = false;
+
+ if (check_ssid &&
+ (match_ssid_len != ssid->ssid_len ||
+ os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ return false;
+ }
+
+ if (ssid->bssid_set &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ return false;
+ }
+
+ /* check blacklist */
+ if (ssid->num_bssid_blacklist &&
+ addr_in_list(bss->bssid, ssid->bssid_blacklist,
+ ssid->num_bssid_blacklist)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
+ return false;
+ }
+
+ /* if there is a whitelist, only accept those APs */
+ if (ssid->num_bssid_whitelist &&
+ !addr_in_list(bss->bssid, ssid->bssid_whitelist,
+ ssid->num_bssid_whitelist)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
+ return false;
+ }
+
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, debug_print))
+ return false;
+
+ if (!osen && !wpa &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_WEP
+ if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
+ return false;
+ }
+#endif /* CONFIG_WEP */
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
+ return false;
+ }
+
+ if (!wpa_supplicant_match_privacy(bss, ssid)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy mismatch");
+ return false;
+ }
+
+ if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
+ return false;
+ }
+
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
+ return false;
+ }
+
+ if (!freq_allowed(ssid->freq_list, bss->freq)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
+ return false;
+ }
+
+#ifdef CONFIG_MESH
+ if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
+ return false;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!rate_match(wpa_s, ssid, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
+ return false;
+ }
+
+#ifdef CONFIG_SAE
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE-PK required, but not supported by the AP");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
+ return false;
+ }
+#endif /* !CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group &&
+ !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
+ !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ return false;
+ }
+
+ if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
+ struct wpabuf *p2p_ie;
+ u8 dev_addr[ETH_ALEN];
+
+ ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+ if (!ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
+ return false;
+ }
+ p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (!p2p_ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
+ return false;
+ }
+
+ if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0 ||
+ os_memcmp(dev_addr, ssid->go_p2p_dev_addr, ETH_ALEN) != 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
+ wpabuf_free(p2p_ie);
+ return false;
+ }
+ wpabuf_free(p2p_ie);
+ }
+
+ /*
+ * TODO: skip the AP if its P2P IE has Group Formation bit set in the
+ * P2P Group Capability Bitmap and we are not in Group Formation with
+ * that device.
+ */
+#endif /* CONFIG_P2P */
+
+ if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time)) {
+ struct os_reltime diff;
+
+ os_reltime_sub(&wpa_s->scan_min_time, &bss->last_update, &diff);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
+ (unsigned int) diff.sec,
+ (unsigned int) diff.usec);
+ return false;
+ }
+#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
+ assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ if (assoc_disallow && assoc_disallow[1] >= 1) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
+ assoc_disallow[2]);
+ return false;
+ }
+
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - AP temporarily disallowed");
+ return false;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_DPP
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
+ !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+ (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no PMKSA entry for DPP");
+ return false;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk == SAE_PK_MODE_AUTOMATIC &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))) &&
+ !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
+ sae_pk_acceptable_bss_with_pk(wpa_s, bss, ssid, match_ssid,
+ match_ssid_len)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - another acceptable BSS with SAE-PK in the same ESS");
+ return false;
+ }
+#endif /* CONFIG_SAE_PK */
+
+ if (bss->ssid_len == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no SSID known for the BSS");
+ return false;
+ }
+
+ /* Matching configuration found */
+ return true;
+}
+
+
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
- int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen, rsn_osen = 0;
-#ifdef CONFIG_MBO
- const u8 *assoc_disallow;
-#endif /* CONFIG_MBO */
+ int osen;
const u8 *match_ssid;
size_t match_ssid_len;
- struct wpa_ie_data data;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
wpa_ie_len = ie ? ie[1] : 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
rsn_ie_len = ie ? ie[1] : 0;
- if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
- (data.key_mgmt & WPA_KEY_MGMT_OSEN))
- rsn_osen = 1;
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
@@ -1180,299 +1555,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
return NULL;
}
- wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
-
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
- int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
- int res;
-
- if (wpas_network_disabled(wpa_s, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
- continue;
- }
-
- res = wpas_temp_disabled(wpa_s, ssid);
- if (res > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - disabled temporarily for %d second(s)",
- res);
- continue;
- }
-
-#ifdef CONFIG_WPS
- if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - blacklisted (WPS)");
- continue;
- }
-
- if (wpa && ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
-
- if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
- /* Only allow wildcard SSID match if an AP
- * advertises active WPS operation that matches
- * with our mode. */
- check_ssid = 1;
- if (ssid->ssid_len == 0 &&
- wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
- check_ssid = 0;
- }
-#endif /* CONFIG_WPS */
-
- if (ssid->bssid_set && ssid->ssid_len == 0 &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
- check_ssid = 0;
-
- if (check_ssid &&
- (match_ssid_len != ssid->ssid_len ||
- os_memcmp(match_ssid, ssid->ssid, match_ssid_len) != 0)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SSID mismatch");
- continue;
- }
-
- if (ssid->bssid_set &&
- os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID mismatch");
- continue;
- }
-
- /* check blacklist */
- if (ssid->num_bssid_blacklist &&
- addr_in_list(bss->bssid, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
- continue;
- }
-
- /* if there is a whitelist, only accept those APs */
- if (ssid->num_bssid_whitelist &&
- !addr_in_list(bss->bssid, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
- continue;
- }
-
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
- debug_print))
- continue;
-
- if (!osen && !wpa &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
- !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-WPA network not allowed");
- continue;
- }
-
-#ifdef CONFIG_WEP
- if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
- has_wep_key(ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - ignore WPA/WPA2 AP for WEP network block");
- continue;
- }
-#endif /* CONFIG_WEP */
-
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen &&
- !rsn_osen) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-OSEN network not allowed");
- continue;
- }
-
- if (!wpa_supplicant_match_privacy(bss, ssid)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - privacy mismatch");
- continue;
- }
-
- if (ssid->mode != WPAS_MODE_MESH && !bss_is_ess(bss) &&
- !bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - not ESS, PBSS, or MBSS");
- continue;
- }
-
- if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - PBSS mismatch (ssid %d bss %d)",
- ssid->pbss, bss_is_pbss(bss));
- continue;
- }
-
- if (!freq_allowed(ssid->freq_list, bss->freq)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed");
- continue;
- }
-
-#ifdef CONFIG_MESH
- if (ssid->mode == WPAS_MODE_MESH && ssid->frequency > 0 &&
- ssid->frequency != bss->freq) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - frequency not allowed (mesh)");
- continue;
- }
-#endif /* CONFIG_MESH */
-
- if (!rate_match(wpa_s, ssid, bss, debug_print)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - rate sets do not match");
- continue;
- }
-
-#ifdef CONFIG_SAE
- if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
- wpa_s->conf->sae_pwe != 3 &&
- wpa_key_mgmt_sae(ssid->key_mgmt) &&
- (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
- ie[1] < 1 ||
- !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - SAE H2E required, but not supported by the AP");
- continue;
- }
-#endif /* CONFIG_SAE */
-
-#ifndef CONFIG_IBSS_RSN
- if (ssid->mode == WPAS_MODE_IBSS &&
- !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
- WPA_KEY_MGMT_WPA_NONE))) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - IBSS RSN not supported in the build");
- continue;
- }
-#endif /* !CONFIG_IBSS_RSN */
-
-#ifdef CONFIG_P2P
- if (ssid->p2p_group &&
- !wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
- !wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P IE seen");
- continue;
- }
-
- if (!is_zero_ether_addr(ssid->go_p2p_dev_addr)) {
- struct wpabuf *p2p_ie;
- u8 dev_addr[ETH_ALEN];
-
- ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
- if (ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no P2P element");
- continue;
- }
- p2p_ie = wpa_bss_get_vendor_ie_multi(
- bss, P2P_IE_VENDOR_TYPE);
- if (p2p_ie == NULL) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - could not fetch P2P element");
- continue;
- }
-
- if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
- || os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
- ETH_ALEN) != 0) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no matching GO P2P Device Address in P2P element");
- wpabuf_free(p2p_ie);
- continue;
- }
- wpabuf_free(p2p_ie);
- }
-
- /*
- * TODO: skip the AP if its P2P IE has Group Formation
- * bit set in the P2P Group Capability Bitmap and we
- * are not in Group Formation with that device.
- */
-#endif /* CONFIG_P2P */
-
- if (os_reltime_before(&bss->last_update, &wpa_s->scan_min_time))
- {
- struct os_reltime diff;
-
- os_reltime_sub(&wpa_s->scan_min_time,
- &bss->last_update, &diff);
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
- (unsigned int) diff.sec,
- (unsigned int) diff.usec);
- continue;
- }
-#ifdef CONFIG_MBO
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->ignore_assoc_disallow)
- goto skip_assoc_disallow;
-#endif /* CONFIG_TESTING_OPTIONS */
- assoc_disallow = wpas_mbo_get_bss_attr(
- bss, MBO_ATTR_ID_ASSOC_DISALLOW);
- if (assoc_disallow && assoc_disallow[1] >= 1) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO association disallowed (reason %u)",
- assoc_disallow[2]);
- continue;
- }
-
- if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - AP temporarily disallowed");
- continue;
- }
-#ifdef CONFIG_TESTING_OPTIONS
- skip_assoc_disallow:
-#endif /* CONFIG_TESTING_OPTIONS */
-#endif /* CONFIG_MBO */
-
-#ifdef CONFIG_DPP
- if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
- !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
- (!ssid->dpp_connector ||
- !ssid->dpp_netaccesskey ||
- !ssid->dpp_csign)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - no PMKSA entry for DPP");
- continue;
- }
-#endif /* CONFIG_DPP */
-
- /* Matching configuration found */
- return ssid;
+ if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
+ bss, e, debug_print))
+ return ssid;
}
/* No matching configuration found */
@@ -1772,52 +1858,19 @@ wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s,
return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr);
}
-#endif /* CONFIG_NO_ROAMING */
-
-static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
- struct wpa_bss *selected,
- struct wpa_ssid *ssid)
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *selected)
{
- struct wpa_bss *current_bss = NULL;
-#ifndef CONFIG_NO_ROAMING
int min_diff, diff;
int to_5ghz;
int cur_level;
unsigned int cur_est, sel_est;
struct wpa_signal_info si;
int cur_snr = 0;
-#endif /* CONFIG_NO_ROAMING */
-
- if (wpa_s->reassociate)
- return 1; /* explicit request to reassociate */
- if (wpa_s->wpa_state < WPA_ASSOCIATED)
- return 1; /* we are not associated; continue */
- if (wpa_s->current_ssid == NULL)
- return 1; /* unknown current SSID */
- if (wpa_s->current_ssid != ssid)
- return 1; /* different network block */
-
- if (wpas_driver_bss_selection(wpa_s))
- return 0; /* Driver-based roaming */
-
- if (wpa_s->current_ssid->ssid)
- current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
- wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->ssid_len);
- if (!current_bss)
- current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
-
- if (!current_bss)
- return 1; /* current BSS not seen in scan results */
-
- if (current_bss == selected)
- return 0;
-
- if (selected->last_update_idx > current_bss->last_update_idx)
- return 1; /* current BSS not seen in the last scan */
+ int ret = 0;
-#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
" freq=%d level=%d snr=%d est_throughput=%u",
@@ -1936,13 +1989,64 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - too small difference in signal level (%d < %d)",
diff, min_diff);
- return 0;
+ ret = 0;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
+ ret = 1;
}
+ wpa_msg_ctrl(wpa_s, MSG_INFO, "%scur_bssid=" MACSTR
+ " cur_freq=%d cur_level=%d cur_est=%d sel_bssid=" MACSTR
+ " sel_freq=%d sel_level=%d sel_est=%d",
+ ret ? WPA_EVENT_DO_ROAM : WPA_EVENT_SKIP_ROAM,
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, cur_level, cur_est,
+ MAC2STR(selected->bssid),
+ selected->freq, selected->level, sel_est);
+ return ret;
+}
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Allow reassociation due to difference in signal level (%d >= %d)",
- diff, min_diff);
- return 1;
+#endif /* CONFIG_NO_ROAMING */
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *selected,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_bss *current_bss = NULL;
+
+ if (wpa_s->reassociate)
+ return 1; /* explicit request to reassociate */
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
+ return 1; /* we are not associated; continue */
+ if (wpa_s->current_ssid == NULL)
+ return 1; /* unknown current SSID */
+ if (wpa_s->current_ssid != ssid)
+ return 1; /* different network block */
+
+ if (wpas_driver_bss_selection(wpa_s))
+ return 0; /* Driver-based roaming */
+
+ if (wpa_s->current_ssid->ssid)
+ current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid_len);
+ if (!current_bss)
+ current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+ if (!current_bss)
+ return 1; /* current BSS not seen in scan results */
+
+ if (current_bss == selected)
+ return 0;
+
+ if (selected->last_update_idx > current_bss->last_update_idx)
+ return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+ return wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
+ selected);
#else /* CONFIG_NO_ROAMING */
return 0;
#endif /* CONFIG_NO_ROAMING */
@@ -2574,11 +2678,11 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
{
int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R || CONFIG_OWE */
+ bool bssid_known;
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+ bssid_known = wpa_drv_get_bssid(wpa_s, bssid) == 0;
if (data->assoc_info.req_ies)
wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
data->assoc_info.req_ies_len);
@@ -2695,7 +2799,7 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_OWE
if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE &&
- (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ (!bssid_known ||
owe_process_assoc_resp(wpa_s->wpa, bssid,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len) < 0)) {
@@ -2730,7 +2834,7 @@ no_pfs:
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2790,7 +2894,7 @@ no_pfs:
/* Process FT when SME is in the driver */
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
wpa_ft_is_completed(wpa_s->wpa)) {
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ if (!bssid_known ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len,
@@ -2808,6 +2912,11 @@ no_pfs:
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
+ if (bssid_known)
+ wpas_handle_assoc_resp_mscs(wpa_s, bssid,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+
/* WPA/RSN IE from Beacon/ProbeResp */
p = data->assoc_info.beacon_ies;
l = data->assoc_info.beacon_ies_len;
@@ -4141,6 +4250,13 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
}
#endif /* CONFIG_DPP */
+ if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+ payload[0] == ROBUST_AV_MSCS_RESP) {
+ wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
+ payload + 1, plen - 1);
+ return;
+ }
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
if (wpa_s->ifmsh)
@@ -4841,7 +4957,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_AP */
- sme_event_ch_switch(wpa_s);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+ sme_event_ch_switch(wpa_s);
+
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index 1883545..9f7fefb 100755
--- a/wpa_supplicant/examples/dpp-nfc.py
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -7,6 +7,8 @@
# This software may be distributed under the terms of the BSD license.
# See README for more details.
+import binascii
+import errno
import os
import struct
import sys
@@ -29,20 +31,28 @@ init_on_touch = False
in_raw_mode = False
prev_tcgetattr = 0
no_input = False
-srv = None
continue_loop = True
terminate_now = False
summary_file = None
success_file = None
-my_crn_ready = False
-my_crn = None
-peer_crn = None
-hs_sent = False
+netrole = None
+operation_success = False
mutex = threading.Lock()
-def summary(txt):
+C_NORMAL = '\033[0m'
+C_RED = '\033[91m'
+C_GREEN = '\033[92m'
+C_YELLOW = '\033[93m'
+C_BLUE = '\033[94m'
+C_MAGENTA = '\033[95m'
+C_CYAN = '\033[96m'
+
+def summary(txt, color=None):
with mutex:
- print(txt)
+ if color:
+ print(color + txt + C_NORMAL)
+ else:
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -67,15 +77,18 @@ def wpas_connect():
return None
for ctrl in ifaces:
- if ifname:
- if ifname not in ctrl:
- continue
+ if ifname and ifname not in ctrl:
+ continue
+ if os.path.basename(ctrl).startswith("p2p-dev-"):
+ # skip P2P management interface
+ continue
try:
summary("Trying to use control interface " + ctrl)
wpas = wpaspy.Ctrl(ctrl)
return wpas
except Exception as e:
pass
+ summary("Could not connect to wpa_supplicant")
return None
def dpp_nfc_uri_process(uri):
@@ -84,7 +97,7 @@ def dpp_nfc_uri_process(uri):
return False
peer_id = wpas.request("DPP_NFC_URI " + uri)
if "FAIL" in peer_id:
- summary("Could not parse DPP URI from NFC URI record")
+ summary("Could not parse DPP URI from NFC URI record", color=C_RED)
return False
peer_id = int(peer_id)
summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
@@ -99,7 +112,7 @@ def dpp_nfc_uri_process(uri):
summary("Initiate DPP authentication: " + cmd)
res = wpas.request(cmd)
if "OK" not in res:
- summary("Failed to initiate DPP Authentication")
+ summary("Failed to initiate DPP Authentication", color=C_RED)
return False
summary("DPP Authentication initiated")
return True
@@ -110,20 +123,20 @@ def dpp_hs_tag_read(record):
return False
summary(record)
if len(record.data) < 5:
- summary("Too short DPP HS")
+ summary("Too short DPP HS", color=C_RED)
return False
if record.data[0] != 0:
- summary("Unexpected URI Identifier Code")
+ summary("Unexpected URI Identifier Code", color=C_RED)
return False
uribuf = record.data[1:]
try:
uri = uribuf.decode()
except:
- summary("Invalid URI payload")
+ summary("Invalid URI payload", color=C_RED)
return False
summary("URI: " + uri)
if not uri.startswith("DPP:"):
- summary("Not a DPP URI")
+ summary("Not a DPP URI", color=C_RED)
return False
return dpp_nfc_uri_process(uri)
@@ -179,12 +192,18 @@ def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
raise Exception("Failed to generate bootstrapping info")
return int(res)
-def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
+def wpas_get_nfc_uri(start_listen=True, pick_channel=False, chan_override=None):
+ listen_freq = 2412
wpas = wpas_connect()
if wpas is None:
return None
global own_id, chanlist
- chan = chanlist
+ if chan_override:
+ chan = chan_override
+ else:
+ chan = chanlist
+ if chan and chan.startswith("81/"):
+ listen_freq = int(chan[3:].split(',')[0]) * 5 + 2407
if chan is None and get_status_field(wpas, "bssid[0]"):
freq = get_status_field(wpas, "freq")
if freq:
@@ -192,15 +211,23 @@ def wpas_get_nfc_uri(start_listen=True, pick_channel=False):
if freq >= 2412 and freq <= 2462:
chan = "81/%d" % ((freq - 2407) / 5)
summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
+ listen_freq = freq
if chan is None and pick_channel:
chan = "81/6"
summary("Use channel 2437 MHz since no other preference provided")
+ listen_freq = 2437
own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
if "FAIL" in res:
return None
if start_listen:
- wpas.request("DPP_LISTEN 2412 netrole=configurator")
+ cmd = "DPP_LISTEN %d" % listen_freq
+ global netrole
+ if netrole:
+ cmd += " netrole=" + netrole
+ res2 = wpas.request(cmd)
+ if "OK" not in res2:
+ raise Exception("Failed to start listen operation (%s)" % cmd)
return res
def wpas_report_handover_req(uri):
@@ -219,82 +246,180 @@ def wpas_report_handover_sel(uri):
cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
return wpas.request(cmd)
-def dpp_handover_client(llc):
- uri = wpas_get_nfc_uri(start_listen=False)
+def dpp_handover_client(handover, alt=False):
+ summary("About to start run_dpp_handover_client (alt=%s)" % str(alt))
+ if alt:
+ handover.i_m_selector = False
+ run_dpp_handover_client(handover, alt)
+ summary("Done run_dpp_handover_client (alt=%s)" % str(alt))
+
+def run_client_alt(handover, alt):
+ if handover.start_client_alt and not alt:
+ handover.start_client_alt = False
+ summary("Try to send alternative handover request")
+ dpp_handover_client(handover, alt=True)
+
+class HandoverClient(nfc.handover.HandoverClient):
+ def __init__(self, handover, llc):
+ super(HandoverClient, self).__init__(llc)
+ self.handover = handover
+
+ def recv_records(self, timeout=None):
+ msg = self.recv_octets(timeout)
+ if msg is None:
+ return None
+ records = list(ndef.message_decoder(msg, 'relax'))
+ if records and records[0].type == 'urn:nfc:wkt:Hs':
+ summary("Handover client received message '{0}'".format(records[0].type))
+ return list(ndef.message_decoder(msg, 'relax'))
+ summary("Handover client received invalid message: %s" + binascii.hexlify(msg))
+ return None
+
+ def recv_octets(self, timeout=None):
+ start = time.time()
+ msg = bytearray()
+ while True:
+ poll_timeout = 0.1 if timeout is None or timeout > 0.1 else timeout
+ if not self.socket.poll('recv', poll_timeout):
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ try:
+ r = self.socket.recv()
+ if r is None:
+ return None
+ msg += r
+ except TypeError:
+ return b''
+ try:
+ list(ndef.message_decoder(msg, 'strict', {}))
+ return bytes(msg)
+ except ndef.DecodeError:
+ if timeout:
+ timeout -= time.time() - start
+ if timeout <= 0:
+ return None
+ start = time.time()
+ continue
+ return None
+
+def run_dpp_handover_client(handover, alt=False):
+ chan_override = None
+ if alt:
+ chan_override = handover.altchanlist
+ handover.alt_proposal_used = True
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI (alt=%s)" % str(alt))
+ uri = test_alt_uri if alt else test_uri
+ else:
+ uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override)
if uri is None:
- summary("Cannot start handover client - no bootstrap URI available")
+ summary("Cannot start handover client - no bootstrap URI available",
+ color=C_RED)
return
+ handover.my_uri = uri
uri = ndef.UriRecord(uri)
summary("NFC URI record for DPP: " + str(uri))
carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
- crn = os.urandom(2)
+ global test_crn
+ if test_crn:
+ prev, = struct.unpack('>H', test_crn)
+ summary("TEST MODE: Use specified crn %d" % prev)
+ crn = test_crn
+ test_crn = struct.pack('>H', prev + 0x10)
+ else:
+ crn = os.urandom(2)
hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
hr.add_alternative_carrier('active', carrier.name)
message = [hr, carrier]
summary("NFC Handover Request message for DPP: " + str(message))
- global peer_crn
- if peer_crn is not None:
+ if handover.peer_crn is not None and not alt:
summary("NFC handover request from peer was already received - do not send own")
return
- client = nfc.handover.HandoverClient(llc)
- try:
- summary("Trying to initiate NFC connection handover")
- client.connect()
- summary("Connected for handover")
- except nfc.llcp.ConnectRefused:
- summary("Handover connection refused")
- client.close()
- return
- except Exception as e:
- summary("Other exception: " + str(e))
- client.close()
- return
+ if handover.client:
+ summary("Use already started handover client")
+ client = handover.client
+ else:
+ summary("Start handover client")
+ client = HandoverClient(handover, handover.llc)
+ try:
+ summary("Trying to initiate NFC connection handover")
+ client.connect()
+ summary("Connected for handover")
+ except nfc.llcp.ConnectRefused:
+ summary("Handover connection refused")
+ client.close()
+ return
+ except Exception as e:
+ summary("Other exception: " + str(e))
+ client.close()
+ return
+ handover.client = client
- if peer_crn is not None:
+ if handover.peer_crn is not None and not alt:
summary("NFC handover request from peer was already received - do not send own")
- client.close()
return
summary("Sending handover request")
- global my_crn, my_crn_ready, hs_sent
- my_crn_ready = True
+ handover.my_crn_ready = True
if not client.send_records(message):
- my_crn_ready = False
- summary("Failed to send handover request")
- client.close()
+ handover.my_crn_ready = False
+ summary("Failed to send handover request", color=C_RED)
+ run_client_alt(handover, alt)
return
- my_crn, = struct.unpack('>H', crn)
+ handover.my_crn, = struct.unpack('>H', crn)
summary("Receiving handover response")
try:
+ start = time.time()
message = client.recv_records(timeout=3.0)
+ end = time.time()
+ summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start))
except Exception as e:
# This is fine if we are the handover selector
- if hs_sent:
+ if handover.hs_sent:
summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
+ elif handover.alt_proposal_used and not alt:
+ summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e))
else:
- summary("Client receive failed: %s" % str(e))
+ summary("Client receive failed: %s" % str(e), color=C_RED)
message = None
if message is None:
- if hs_sent:
+ if handover.hs_sent:
summary("No response received as expected since I'm the handover server")
+ elif handover.alt_proposal_used and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal was also used")
+ elif handover.try_own and not alt:
+ summary("No response received for initial proposal as expected since alternative proposal will also be sent")
else:
- summary("No response received")
- client.close()
+ summary("No response received", color=C_RED)
+ run_client_alt(handover, alt)
return
summary("Received message: " + str(message))
if len(message) < 1 or \
not isinstance(message[0], ndef.HandoverSelectRecord):
summary("Response was not Hs - received: " + message.type)
- client.close()
return
summary("Received handover select message")
summary("alternative carriers: " + str(message[0].alternative_carriers))
+ if handover.i_m_selector:
+ summary("Ignore the received select since I'm the handover selector")
+ run_client_alt(handover, alt)
+ return
+
+ if handover.alt_proposal_used and not alt:
+ summary("Ignore received handover select for the initial proposal since alternative proposal was sent")
+ client.close()
+ return
dpp_found = False
for carrier in message:
@@ -303,15 +428,19 @@ def dpp_handover_client(llc):
summary("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.dpp":
if len(carrier.data) == 0 or carrier.data[0] != 0:
- summary("URI Identifier Code 'None' not seen")
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
continue
summary("DPP carrier type match - send to wpa_supplicant")
dpp_found = True
uri = carrier.data[1:].decode("utf-8")
summary("DPP URI: " + uri)
+ handover.peer_uri = uri
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ break
res = wpas_report_handover_sel(uri)
if res is None or "FAIL" in res:
- summary("DPP handover report rejected")
+ summary("DPP handover report rejected", color=C_RED)
break
success_report("DPP handover reported successfully (initiator)")
@@ -331,7 +460,7 @@ def dpp_handover_client(llc):
# TODO: Single Configurator instance
res = wpas.request("DPP_CONFIGURATOR_ADD")
if "FAIL" in res:
- summary("Failed to initiate Configurator")
+ summary("Failed to initiate Configurator", color=C_RED)
break
conf_id = int(res)
extra = " conf=sta-dpp configurator=%d" % conf_id
@@ -341,17 +470,23 @@ def dpp_handover_client(llc):
cmd += extra
res = wpas.request(cmd)
if "FAIL" in res:
- summary("Failed to initiate DPP authentication")
+ summary("Failed to initiate DPP authentication", color=C_RED)
break
- if not dpp_found:
+ if not dpp_found and handover.no_alt_proposal:
+ summary("DPP carrier not seen in response - do not allow alternative proposal anymore")
+ elif not dpp_found:
summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
- client.close()
+ handover.alt_proposal = True
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
summary("Returning from dpp_handover_client")
return
summary("Remove peer")
- client.close()
+ handover.close()
summary("Done with handover")
global only_one
if only_one:
@@ -360,22 +495,67 @@ def dpp_handover_client(llc):
continue_loop = False
global no_wait
- if no_wait:
- print("Trying to exit..")
+ if no_wait or only_one:
+ summary("Trying to exit..")
global terminate_now
terminate_now = True
summary("Returning from dpp_handover_client")
class HandoverServer(nfc.handover.HandoverServer):
- def __init__(self, llc):
+ def __init__(self, handover, llc):
super(HandoverServer, self).__init__(llc)
self.sent_carrier = None
self.ho_server_processing = False
self.success = False
- self.try_own = False
+ self.llc = llc
+ self.handover = handover
+
+ def serve(self, socket):
+ peer_sap = socket.getpeername()
+ summary("Serving handover client on remote sap {0}".format(peer_sap))
+ send_miu = socket.getsockopt(nfc.llcp.SO_SNDMIU)
+ try:
+ while socket.poll("recv"):
+ req = bytearray()
+ while socket.poll("recv"):
+ r = socket.recv()
+ if r is None:
+ return None
+ summary("Received %d octets" % len(r))
+ req += r
+ if len(req) == 0:
+ continue
+ try:
+ list(ndef.message_decoder(req, 'strict', {}))
+ except ndef.DecodeError:
+ continue
+ summary("Full message received")
+ resp = self._process_request_data(req)
+ if resp is None or len(resp) == 0:
+ summary("No handover select to send out - wait for a possible alternative handover request")
+ handover.alt_proposal = True
+ req = bytearray()
+ continue
+
+ for offset in range(0, len(resp), send_miu):
+ if not socket.send(resp[offset:offset + send_miu]):
+ summary("Failed to send handover select - connection closed")
+ return
+ summary("Sent out full handover select")
+ if handover.terminate_on_hs_send_completion:
+ handover.delayed_exit()
+
+ except nfc.llcp.Error as e:
+ global terminate_now
+ summary("HandoverServer exception: %s" % e,
+ color=None if e.errno == errno.EPIPE or terminate_now else C_RED)
+ finally:
+ socket.close()
+ summary("Handover serve thread exiting")
def process_handover_request_message(self, records):
+ handover = self.handover
self.ho_server_processing = True
global in_raw_mode
was_in_raw_mode = in_raw_mode
@@ -384,33 +564,33 @@ class HandoverServer(nfc.handover.HandoverServer):
print("\n")
summary("HandoverServer - request received: " + str(records))
- global my_crn, peer_crn, my_crn_ready
-
for carrier in records:
if not isinstance(carrier, ndef.HandoverRequestRecord):
continue
if carrier.collision_resolution_number:
- peer_crn = carrier.collision_resolution_number
- summary("peer_crn: %d" % peer_crn)
+ handover.peer_crn = carrier.collision_resolution_number
+ summary("peer_crn: %d" % handover.peer_crn)
- if my_crn is None and my_crn_ready:
+ if handover.my_crn is None and handover.my_crn_ready:
summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
for i in range(10):
- if my_crn is not None:
+ if handover.my_crn is not None:
break
time.sleep(0.01)
- if my_crn is not None:
- summary("my_crn: %d" % my_crn)
+ if handover.my_crn is not None:
+ summary("my_crn: %d" % handover.my_crn)
- if my_crn is not None and peer_crn is not None:
- if my_crn == peer_crn:
+ if handover.my_crn is not None and handover.peer_crn is not None:
+ if handover.my_crn == handover.peer_crn:
summary("Same crn used - automatic collision resolution failed")
# TODO: Should generate a new Handover Request message
return ''
- if ((my_crn & 1) == (peer_crn & 1) and my_crn > peer_crn) or \
- ((my_crn & 1) != (peer_crn & 1) and my_crn < peer_crn):
+ if ((handover.my_crn & 1) == (handover.peer_crn & 1) and \
+ handover.my_crn > handover.peer_crn) or \
+ ((handover.my_crn & 1) != (handover.peer_crn & 1) and \
+ handover.my_crn < handover.peer_crn):
summary("I'm the Handover Selector Device")
- pass
+ handover.i_m_selector = True
else:
summary("Peer is the Handover Selector device")
summary("Ignore the received request.")
@@ -428,61 +608,90 @@ class HandoverServer(nfc.handover.HandoverServer):
if carrier.type == "application/vnd.wfa.dpp":
summary("DPP carrier type match - add DPP carrier record")
if len(carrier.data) == 0 or carrier.data[0] != 0:
- summary("URI Identifier Code 'None' not seen")
+ summary("URI Identifier Code 'None' not seen", color=C_RED)
continue
uri = carrier.data[1:].decode("utf-8")
summary("Received DPP URI: " + uri)
- data = wpas_get_nfc_uri(start_listen=False, pick_channel=True)
+ global test_uri, test_alt_uri
+ if test_uri:
+ summary("TEST MODE: Using specified URI")
+ data = test_sel_uri if test_sel_uri else test_uri
+ elif handover.alt_proposal and handover.altchanlist:
+ summary("Use alternative channel list while processing alternative proposal from peer")
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist,
+ pick_channel=True)
+ else:
+ data = wpas_get_nfc_uri(start_listen=False,
+ pick_channel=True)
summary("Own URI (pre-processing): %s" % data)
- res = wpas_report_handover_req(uri)
+ if test_uri:
+ summary("TEST MODE: Fake processing")
+ res = "OK"
+ data += " [%s]" % uri
+ else:
+ res = wpas_report_handover_req(uri)
if res is None or "FAIL" in res:
- summary("DPP handover request processing failed")
+ summary("DPP handover request processing failed",
+ color=C_RED)
+ if handover.altchanlist:
+ data = wpas_get_nfc_uri(start_listen=False,
+ chan_override=handover.altchanlist)
+ summary("Own URI (try another channel list): %s" % data)
+ continue
+
+ if test_alt_uri:
+ summary("TEST MODE: Reject initial proposal")
continue
found = True
- wpas = wpas_connect()
- if wpas is None:
- continue
- global own_id
- data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
- if "FAIL" in data:
- continue
+ if not test_uri:
+ wpas = wpas_connect()
+ if wpas is None:
+ continue
+ global own_id
+ data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
+ if "FAIL" in data:
+ continue
summary("Own URI (post-processing): %s" % data)
+ handover.my_uri = data
+ handover.peer_uri = uri
uri = ndef.UriRecord(data)
summary("Own bootstrapping NFC URI record: " + str(uri))
- info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
- freq = None
- for line in info.splitlines():
- if line.startswith("use_freq="):
- freq = int(line.split('=')[1])
- if freq is None or freq == 0:
- summary("No channel negotiated over NFC - use channel 6")
- freq = 2437
- else:
- summary("Negotiated channel: %d MHz" % freq)
- if get_status_field(wpas, "bssid[0]"):
- summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
- if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
- summary("Enable beaconing to have radio ready for RX")
- wpas.request("DISABLE")
- wpas.request("SET start_disabled 0")
- wpas.request("ENABLE")
- cmd = "DPP_LISTEN %d" % freq
- global enrollee_only
- global configurator_only
- if enrollee_only:
- cmd += " role=enrollee"
- elif configurator_only:
- cmd += " role=configurator"
- summary(cmd)
- res = wpas.request(cmd)
- if "OK" not in res:
- summary("Failed to start DPP listen")
- break
+ if not test_uri:
+ info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
+ freq = None
+ for line in info.splitlines():
+ if line.startswith("use_freq="):
+ freq = int(line.split('=')[1])
+ if freq is None or freq == 0:
+ summary("No channel negotiated over NFC - use channel 6")
+ freq = 2437
+ else:
+ summary("Negotiated channel: %d MHz" % freq)
+ if get_status_field(wpas, "bssid[0]"):
+ summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
+ if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
+ summary("Enable beaconing to have radio ready for RX")
+ wpas.request("DISABLE")
+ wpas.request("SET start_disabled 0")
+ wpas.request("ENABLE")
+ cmd = "DPP_LISTEN %d" % freq
+ global enrollee_only
+ global configurator_only
+ if enrollee_only:
+ cmd += " role=enrollee"
+ elif configurator_only:
+ cmd += " role=configurator"
+ summary(cmd)
+ res = wpas.request(cmd)
+ if "OK" not in res:
+ summary("Failed to start DPP listen", color=C_RED)
+ break
carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
summary("Own DPP carrier record: " + str(carrier))
@@ -492,11 +701,26 @@ class HandoverServer(nfc.handover.HandoverServer):
summary("Sending handover select: " + str(sel))
if found:
+ summary("Handover completed successfully")
+ handover.terminate_on_hs_send_completion = True
self.success = True
+ handover.hs_sent = True
+ handover.i_m_selector = True
+ elif handover.no_alt_proposal:
+ summary("Do not try alternative proposal anymore - handover failed",
+ color=C_RED)
+ handover.hs_sent = True
else:
- self.try_own = True
- global hs_sent
- hs_sent = True
+ summary("Try to initiate with alternative parameters")
+ handover.try_own = True
+ handover.hs_sent = False
+ handover.no_alt_proposal = True
+ if handover.client_thread:
+ handover.start_client_alt = True
+ else:
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(self.llc, True))
+ handover.client_thread.start()
return sel
def clear_raw_mode():
@@ -553,17 +777,25 @@ def dpp_tag_read(tag):
def rdwr_connected_write_tag(tag):
summary("Tag found - writing - " + str(tag))
+ if not tag.ndef:
+ summary("Not a formatted NDEF tag", color=C_RED)
+ return
if not tag.ndef.is_writeable:
- summary("Not a writable tag")
+ summary("Not a writable tag", color=C_RED)
return
global dpp_tag_data
if tag.ndef.capacity < len(dpp_tag_data):
summary("Not enough room for the message")
return
- tag.ndef.records = dpp_tag_data
+ try:
+ tag.ndef.records = dpp_tag_data
+ except ValueError as e:
+ summary("Writing the tag failed: %s" % str(e), color=C_RED)
+ return
success_report("Tag write succeeded")
- summary("Done - remove tag")
- global only_one
+ summary("Tag writing completed - remove tag", color=C_GREEN)
+ global only_one, operation_success
+ operation_success = True
if only_one:
global continue_loop
continue_loop = False
@@ -574,7 +806,7 @@ def write_nfc_uri(clf, wait_remove=True):
summary("Write NFC URI record")
data = wpas_get_nfc_uri()
if data is None:
- summary("Could not get NFC URI from wpa_supplicant")
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
return
global dpp_sel_wait_remove
@@ -583,7 +815,7 @@ def write_nfc_uri(clf, wait_remove=True):
uri = ndef.UriRecord(data)
summary(uri)
- summary("Touch an NFC tag")
+ summary("Touch an NFC tag to write URI record", color=C_CYAN)
global dpp_tag_data
dpp_tag_data = [uri]
clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
@@ -592,7 +824,7 @@ def write_nfc_hs(clf, wait_remove=True):
summary("Write NFC Handover Select record on a tag")
data = wpas_get_nfc_uri()
if data is None:
- summary("Could not get NFC URI from wpa_supplicant")
+ summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
return
global dpp_sel_wait_remove
@@ -606,7 +838,7 @@ def write_nfc_hs(clf, wait_remove=True):
summary(hs)
summary(carrier)
- summary("Touch an NFC tag")
+ summary("Touch an NFC tag to write HS record", color=C_CYAN)
global dpp_tag_data
dpp_tag_data = [hs, carrier]
summary(dpp_tag_data)
@@ -624,17 +856,24 @@ def rdwr_connected(tag):
global continue_loop
continue_loop = False
else:
- summary("Not an NDEF tag - remove tag")
+ summary("Not an NDEF tag - remove tag", color=C_RED)
return True
return not no_wait
-def llcp_worker(llc):
+def llcp_worker(llc, try_alt):
+ global handover
+ print("Start of llcp_worker()")
+ if try_alt:
+ summary("Starting handover client (try_alt)")
+ dpp_handover_client(handover, alt=True)
+ summary("Exiting llcp_worker thread (try_alt)")
+ return
global init_on_touch
if init_on_touch:
- summary("Starting handover client")
- dpp_handover_client(llc)
- summary("Exiting llcp_worker thread (init_in_touch)")
+ summary("Starting handover client (init_on_touch)")
+ dpp_handover_client(handover)
+ summary("Exiting llcp_worker thread (init_on_touch)")
return
global no_input
@@ -642,16 +881,18 @@ def llcp_worker(llc):
summary("Wait for handover to complete")
else:
print("Wait for handover to complete - press 'i' to initiate")
- global srv
- global wait_connection
- while not wait_connection and srv.sent_carrier is None:
- if srv.try_own:
- srv.try_own = False
+ while not handover.wait_connection and handover.srv.sent_carrier is None:
+ if handover.try_own:
+ handover.try_own = False
summary("Try to initiate another handover with own parameters")
- dpp_handover_client(llc)
+ handover.my_crn_ready = False
+ handover.my_crn = None
+ handover.peer_crn = None
+ handover.hs_sent = False
+ dpp_handover_client(handover, alt=True)
summary("Exiting llcp_worker thread (retry with own parameters)")
return
- if srv.ho_server_processing:
+ if handover.srv.ho_server_processing:
time.sleep(0.025)
elif no_input:
time.sleep(0.5)
@@ -661,7 +902,7 @@ def llcp_worker(llc):
continue
clear_raw_mode()
summary("Starting handover client")
- dpp_handover_client(llc)
+ dpp_handover_client(handover)
summary("Exiting llcp_worker thread (manual init)")
return
@@ -672,28 +913,73 @@ def llcp_worker(llc):
print("\r")
summary("Exiting llcp_worker thread")
+class ConnectionHandover():
+ def __init__(self):
+ self.client = None
+ self.client_thread = None
+ self.reset()
+ self.exit_thread = None
+
+ def reset(self):
+ self.wait_connection = False
+ self.my_crn_ready = False
+ self.my_crn = None
+ self.peer_crn = None
+ self.hs_sent = False
+ self.no_alt_proposal = False
+ self.alt_proposal_used = False
+ self.i_m_selector = False
+ self.start_client_alt = False
+ self.terminate_on_hs_send_completion = False
+ self.try_own = False
+ self.my_uri = None
+ self.peer_uri = None
+ self.connected = False
+ self.alt_proposal = False
+
+ def start_handover_server(self, llc):
+ summary("Start handover server")
+ self.llc = llc
+ self.srv = HandoverServer(self, llc)
+
+ def close(self):
+ if self.client:
+ self.client.close()
+ self.client = None
+
+ def run_delayed_exit(self):
+ summary("Trying to exit (delayed)..")
+ time.sleep(0.25)
+ summary("Trying to exit (after wait)..")
+ global terminate_now
+ terminate_now = True
+
+ def delayed_exit(self):
+ global only_one
+ if only_one:
+ self.exit_thread = threading.Thread(target=self.run_delayed_exit)
+ self.exit_thread.start()
+
def llcp_startup(llc):
- summary("Start LLCP server")
- global srv
- srv = HandoverServer(llc)
+ global handover
+ handover.start_handover_server(llc)
return llc
def llcp_connected(llc):
summary("P2P LLCP connected")
- global wait_connection, my_crn, peer_crn, my_crn_ready, hs_sent
- wait_connection = False
- my_crn_ready = False
- my_crn = None
- peer_crn = None
- hs_sent = False
- global srv
- srv.start()
+ global handover
+ handover.connected = True
+ handover.srv.start()
if init_on_touch or not no_input:
- threading.Thread(target=llcp_worker, args=(llc,)).start()
+ handover.client_thread = threading.Thread(target=llcp_worker,
+ args=(llc, False))
+ handover.client_thread.start()
return True
def llcp_release(llc):
summary("LLCP release")
+ global handover
+ handover.close()
return True
def terminate_loop():
@@ -737,22 +1023,53 @@ def main():
help='success file for writing success update')
parser.add_argument('--device', default='usb', help='NFC device to open')
parser.add_argument('--chan', default=None, help='channel list')
+ parser.add_argument('--altchan', default=None, help='alternative channel list')
+ parser.add_argument('--netrole', default=None, help='netrole for Enrollee')
+ parser.add_argument('--test-uri', default=None,
+ help='test mode: initial URI')
+ parser.add_argument('--test-alt-uri', default=None,
+ help='test mode: alternative URI')
+ parser.add_argument('--test-sel-uri', default=None,
+ help='test mode: handover select URI')
+ parser.add_argument('--test-crn', default=None,
+ help='test mode: hardcoded crn')
parser.add_argument('command', choices=['write-nfc-uri',
'write-nfc-hs'],
nargs='?')
args = parser.parse_args()
summary(args)
+ global handover
+ handover = ConnectionHandover()
+
global only_one
only_one = args.only_one
global no_wait
no_wait = args.no_wait
- global chanlist
+ global chanlist, netrole, test_uri, test_alt_uri, test_sel_uri
+ global test_crn
chanlist = args.chan
+ handover.altchanlist = args.altchan
+ netrole = args.netrole
+ test_uri = args.test_uri
+ test_alt_uri = args.test_alt_uri
+ test_sel_uri = args.test_sel_uri
+ if args.test_crn:
+ test_crn = struct.pack('>H', int(args.test_crn))
+ else:
+ test_crn = None
logging.basicConfig(level=args.loglevel)
+ for l in ['nfc.clf.rcs380',
+ 'nfc.clf.transport',
+ 'nfc.clf.device',
+ 'nfc.clf.__init__',
+ 'nfc.llcp',
+ 'nfc.handover']:
+ log = logging.getLogger(l)
+ log.setLevel(args.loglevel)
global init_on_touch
init_on_touch = args.init_on_touch
@@ -788,19 +1105,22 @@ def main():
no_input = True
clf = nfc.ContactlessFrontend()
- global wait_connection
try:
if not clf.open(args.device):
- summary("Could not open connection with an NFC device")
- raise SystemExit
+ summary("Could not open connection with an NFC device", color=C_RED)
+ raise SystemExit(1)
if args.command == "write-nfc-uri":
write_nfc_uri(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
raise SystemExit
if args.command == "write-nfc-hs":
write_nfc_hs(clf, wait_remove=not args.no_wait)
+ if not operation_success:
+ raise SystemExit(1)
raise SystemExit
global continue_loop
@@ -810,8 +1130,14 @@ def main():
clear_raw_mode()
if was_in_raw_mode:
print("\r")
- summary("Waiting for a tag or peer to be touched")
- wait_connection = True
+ if args.handover_only:
+ summary("Waiting a peer to be touched", color=C_MAGENTA)
+ elif args.tag_read_only:
+ summary("Waiting for a tag to be touched", color=C_BLUE)
+ else:
+ summary("Waiting for a tag or peer to be touched",
+ color=C_GREEN)
+ handover.wait_connection = True
try:
if args.tag_read_only:
if not clf.connect(rdwr={'on-connect': rdwr_connected}):
@@ -833,9 +1159,18 @@ def main():
summary("clf.connect failed: " + str(e))
break
- global srv
- if only_one and srv and srv.success:
- raise SystemExit
+ if only_one and handover.connected:
+ role = "selector" if handover.i_m_selector else "requestor"
+ summary("Connection handover result: I'm the %s" % role,
+ color=C_YELLOW)
+ if handover.peer_uri:
+ summary("Peer URI: " + handover.peer_uri, color=C_YELLOW)
+ if handover.my_uri:
+ summary("My URI: " + handover.my_uri, color=C_YELLOW)
+ if not (handover.peer_uri and handover.my_uri):
+ summary("Negotiated connection handover failed",
+ color=C_YELLOW)
+ break
except KeyboardInterrupt:
raise SystemExit
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 4b3fcfc..e60a8c1 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -694,13 +694,15 @@ static void gas_query_start_cb(struct wpa_radio_work *work, int deinit)
return;
}
- if (!query->maintain_addr &&
- wpas_update_random_addr_disassoc(wpa_s) < 0) {
- wpa_msg(wpa_s, MSG_INFO,
- "Failed to assign random MAC address for GAS");
- gas_query_free(query, 1);
- radio_work_done(work);
- return;
+ if (!query->maintain_addr && !wpa_s->conf->gas_rand_mac_addr) {
+ if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Failed to assign random MAC address for GAS");
+ gas_query_free(query, 1);
+ radio_work_done(work);
+ return;
+ }
+ os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
}
gas->work = work;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index a380123..00e1492 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -959,7 +959,9 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
- wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
+ wpa_config_set(ssid, "ieee80211w",
+ wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_REQUIRED ?
+ "2" : "1", 0) < 0 ||
wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
@@ -2748,27 +2750,27 @@ void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
}
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes)
{
struct wpabuf *buf;
struct wpabuf *extra_buf = NULL;
int ret = 0;
- int freq;
struct wpa_bss *bss;
int res;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (!bss) {
+ if (!bss && !freq) {
wpa_printf(MSG_WARNING,
- "ANQP: Cannot send query to unknown BSS "
- MACSTR, MAC2STR(dst));
+ "ANQP: Cannot send query without BSS freq info");
return -1;
}
- wpa_bss_anqp_unshare_alloc(bss);
- freq = bss->freq;
+ if (bss)
+ wpa_bss_anqp_unshare_alloc(bss);
+ if (bss && !freq)
+ freq = bss->freq;
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Query Request to " MACSTR " for %u id(s)",
@@ -2787,6 +2789,13 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
if (mbo_subtypes) {
struct wpabuf *mbo;
+ if (!bss) {
+ wpa_printf(MSG_WARNING,
+ "ANQP: Cannot send MBO query to unknown BSS "
+ MACSTR, MAC2STR(dst));
+ return -1;
+ }
+
mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
if (mbo) {
if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 37ee2e9..77b2c91 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -11,7 +11,7 @@
enum gas_query_result;
-int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq,
u16 info_ids[], size_t num_ids, u32 subtypes,
u32 mbo_subtypes);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index ea62abf..3abbe09 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -533,6 +533,8 @@ static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
if (sta) {
+ if (sta->plink_state == PLINK_ESTAB)
+ hapd->num_plinks--;
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index 983801f..bd97fee 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -22,13 +22,13 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
unsigned int *flags)
{
int i;
- int is_6ghz = op_class >= 131 && op_class <= 135;
+ int is_6ghz = op_class >= 131 && op_class <= 136;
for (i = 0; i < mode->num_channels; i++) {
int chan_is_6ghz;
- chan_is_6ghz = mode->channels[i].freq > 5940 &&
- mode->channels[i].freq <= 7105;
+ chan_is_6ghz = mode->channels[i].freq >= 5935 &&
+ mode->channels[i].freq <= 7115;
if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 4a8f4ff..de49948 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -154,7 +154,8 @@ static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
const u8 *pmk, size_t pmk_len,
- u32 pmk_lifetime, u8 pmk_reauth_threshold)
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
printf("%s - not implemented\n", __func__);
return -1;
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
new file mode 100644
index 0000000..3131551
--- /dev/null
+++ b/wpa_supplicant/robust_av.c
@@ -0,0 +1,157 @@
+/*
+ * wpa_supplicant - Robust AV procedures
+ * Copyright (c) 2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+
+
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf)
+{
+ u8 *len, *len1;
+
+ /* MSCS descriptor element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ wpabuf_put_u8(buf, robust_av->request_type);
+ wpabuf_put_u8(buf, robust_av->up_bitmap);
+ wpabuf_put_u8(buf, robust_av->up_limit);
+ wpabuf_put_le32(buf, robust_av->stream_timeout);
+
+ if (robust_av->request_type != SCS_REQ_REMOVE) {
+ /* TCLAS mask element */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len1 = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_TCLAS_MASK);
+
+ /* Frame classifier */
+ wpabuf_put_data(buf, robust_av->frame_classifier,
+ robust_av->frame_classifier_len);
+ *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+ }
+
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+}
+
+
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+ const u8 *ext_capab = NULL;
+ size_t buf_len;
+ int ret;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return 0;
+
+ if (wpa_s->current_bss)
+ ext_capab = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_EXT_CAPAB);
+
+ if (!ext_capab || ext_capab[1] < 11 || !(ext_capab[12] & 0x20)) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "AP does not support MSCS - could not send MSCS Req");
+ return -1;
+ }
+
+ if (!wpa_s->mscs_setup_done &&
+ wpa_s->robust_av.request_type != SCS_REQ_ADD) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "MSCS: Failed to send MSCS Request: request type invalid");
+ return -1;
+ }
+
+ buf_len = 3 + /* Action frame header */
+ 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "Failed to allocate MSCS req");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
+ wpabuf_put_u8(buf, ROBUST_AV_MSCS_REQ);
+ wpa_s->robust_av.dialog_token++;
+ wpabuf_put_u8(buf, wpa_s->robust_av.dialog_token);
+
+ /* MSCS descriptor element */
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, buf);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS Request", wpabuf_head(buf));
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_INFO, "MSCS: Failed to send MSCS Request");
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf, size_t len)
+{
+ u8 dialog_token;
+ u16 status_code;
+
+ if (len < 3)
+ return;
+
+ dialog_token = *buf++;
+ if (dialog_token != wpa_s->robust_av.dialog_token) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+ dialog_token, wpa_s->robust_av.dialog_token);
+ return;
+ }
+
+ status_code = *buf;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(src), status_code);
+ wpa_s->mscs_setup_done = status_code == WLAN_STATUS_SUCCESS;
+}
+
+
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len)
+{
+ const u8 *mscs_desc_ie, *mscs_status;
+ u16 status;
+
+ /* Process optional MSCS Status subelement when MSCS IE is in
+ * (Re)Association Response frame */
+ if (!ies || ies_len == 0 || !wpa_s->robust_av.valid_config)
+ return;
+
+ mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR);
+ if (!mscs_desc_ie || mscs_desc_ie[1] < 1)
+ return;
+
+ mscs_status = get_ie(mscs_desc_ie, mscs_desc_ie[1],
+ MCSC_SUBELEM_STATUS);
+ if (!mscs_status || mscs_status[1] < 2)
+ return;
+
+ status = WPA_GET_LE16(mscs_status + 2);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR
+ " status_code=%u", MAC2STR(bssid), status);
+ wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index b475730..7415eae 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -2187,6 +2187,60 @@ void scan_snr(struct wpa_scan_res *res)
}
+/* Minimum SNR required to achieve a certain bitrate. */
+struct minsnr_bitrate_entry {
+ int minsnr;
+ unsigned int bitrate; /* in Mbps */
+};
+
+/* VHT needs to be enabled in order to achieve MCS8 and MCS9 rates. */
+static const int vht_mcs = 8;
+
+static const struct minsnr_bitrate_entry vht20_table[] = {
+ { 0, 0 },
+ { 2, 6500 }, /* HT20 MCS0 */
+ { 5, 13000 }, /* HT20 MCS1 */
+ { 9, 19500 }, /* HT20 MCS2 */
+ { 11, 26000 }, /* HT20 MCS3 */
+ { 15, 39000 }, /* HT20 MCS4 */
+ { 18, 52000 }, /* HT20 MCS5 */
+ { 20, 58500 }, /* HT20 MCS6 */
+ { 25, 65000 }, /* HT20 MCS7 */
+ { 29, 78000 }, /* VHT20 MCS8 */
+ { -1, 78000 } /* SNR > 29 */
+};
+
+static const struct minsnr_bitrate_entry vht40_table[] = {
+ { 0, 0 },
+ { 5, 13500 }, /* HT40 MCS0 */
+ { 8, 27000 }, /* HT40 MCS1 */
+ { 12, 40500 }, /* HT40 MCS2 */
+ { 14, 54000 }, /* HT40 MCS3 */
+ { 18, 81000 }, /* HT40 MCS4 */
+ { 21, 108000 }, /* HT40 MCS5 */
+ { 23, 121500 }, /* HT40 MCS6 */
+ { 28, 135000 }, /* HT40 MCS7 */
+ { 32, 162000 }, /* VHT40 MCS8 */
+ { 34, 180000 }, /* VHT40 MCS9 */
+ { -1, 180000 } /* SNR > 34 */
+};
+
+static const struct minsnr_bitrate_entry vht80_table[] = {
+ { 0, 0 },
+ { 8, 29300 }, /* VHT80 MCS0 */
+ { 11, 58500 }, /* VHT80 MCS1 */
+ { 15, 87800 }, /* VHT80 MCS2 */
+ { 17, 117000 }, /* VHT80 MCS3 */
+ { 21, 175500 }, /* VHT80 MCS4 */
+ { 24, 234000 }, /* VHT80 MCS5 */
+ { 26, 263300 }, /* VHT80 MCS6 */
+ { 31, 292500 }, /* VHT80 MCS7 */
+ { 35, 351000 }, /* VHT80 MCS8 */
+ { 37, 390000 }, /* VHT80 MCS9 */
+ { -1, 390000 } /* SNR > 37 */
+};
+
+
static unsigned int interpolate_rate(int snr, int snr0, int snr1,
int rate0, int rate1)
{
@@ -2194,68 +2248,42 @@ static unsigned int interpolate_rate(int snr, int snr0, int snr1,
}
-#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \
- if (snr < (snr1)) \
- return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1))
+static unsigned int max_rate(const struct minsnr_bitrate_entry table[],
+ int snr, bool vht)
+{
+ const struct minsnr_bitrate_entry *prev, *entry = table;
+
+ while ((entry->minsnr != -1) &&
+ (snr >= entry->minsnr) &&
+ (vht || entry - table <= vht_mcs))
+ entry++;
+ if (entry == table)
+ return entry->bitrate;
+ prev = entry - 1;
+ if (entry->minsnr == -1 || (!vht && entry - table > vht_mcs))
+ return prev->bitrate;
+ return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate,
+ entry->bitrate);
+}
+
-static unsigned int max_ht20_rate(int snr, int vht)
+static unsigned int max_ht20_rate(int snr, bool vht)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */
- INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */
- INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */
- INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */
- INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */
- INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */
- INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */
- INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */
- if (!vht)
- return 65000;
- INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */
- return 78000;
+ return max_rate(vht20_table, snr, vht);
}
-static unsigned int max_ht40_rate(int snr, int vht)
+static unsigned int max_ht40_rate(int snr, bool vht)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */
- INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */
- INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */
- INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */
- INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */
- INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */
- INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */
- INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */
- if (!vht)
- return 135000;
- INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */
- INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */
- return 180000;
+ return max_rate(vht40_table, snr, vht);
}
static unsigned int max_vht80_rate(int snr)
{
- if (snr < 0)
- return 0;
- INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */
- INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */
- INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */
- INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */
- INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */
- INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */
- INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */
- INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */
- INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */
- INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */
- return 390000;
+ return max_rate(vht80_table, snr, 1);
}
-#undef INTERPOLATE_RATE
-
unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
const u8 *ies, size_t ies_len, int rate,
@@ -2309,7 +2337,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr, 0);
+ tmp = max_ht20_rate(snr, false);
if (tmp > est)
est = tmp;
}
@@ -2319,7 +2347,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2 &&
(ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr, 0);
+ tmp = max_ht40_rate(snr, false);
if (tmp > est)
est = tmp;
}
@@ -2329,7 +2357,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
/* Use +1 to assume VHT is always faster than HT */
ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP);
if (ie) {
- tmp = max_ht20_rate(snr, 1) + 1;
+ tmp = max_ht20_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
@@ -2337,7 +2365,7 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s,
if (ie && ie[1] >= 2 &&
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
- tmp = max_ht40_rate(snr, 1) + 1;
+ tmp = max_ht40_rate(snr, true) + 1;
if (tmp > est)
est = tmp;
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 3ad0065..592c742 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -128,8 +128,8 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
- use_pt = wpa_s->sme.sae.tmp->h2e;
- use_pk = wpa_s->sme.sae.tmp->pk;
+ use_pt = wpa_s->sme.sae.h2e;
+ use_pk = wpa_s->sme.sae.pk;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -150,10 +150,20 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
use_pt = 1;
#ifdef CONFIG_SAE_PK
if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
- ssid->sae_password && sae_pk_valid_password(ssid->sae_password)) {
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase)))) {
use_pt = 1;
use_pk = true;
}
+
+ if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use PK with the selected AP");
+ return NULL;
+ }
#endif /* CONFIG_SAE_PK */
if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
@@ -184,7 +194,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
if (wpa_s->sme.sae.tmp) {
os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
if (use_pt && use_pk)
- wpa_s->sme.sae.tmp->pk = 1;
+ wpa_s->sme.sae.pk = 1;
#ifdef CONFIG_SAE_PK
os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
ETH_ALEN);
@@ -1260,8 +1270,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpabuf_free(wpa_s->sme.sae_token);
token_pos = data + sizeof(le16);
token_len = len - sizeof(le16);
- if (wpa_s->sme.sae.tmp)
- h2e = wpa_s->sme.sae.tmp->h2e;
+ h2e = wpa_s->sme.sae.h2e;
if (h2e) {
if (token_len < 3) {
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1342,20 +1351,18 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
"SAE: Ignore commit message while waiting for confirm");
return 0;
}
- if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e &&
- status_code == WLAN_STATUS_SUCCESS) {
+ if (wpa_s->sme.sae.h2e && status_code == WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG,
"SAE: Unexpected use of status code 0 in SAE commit when H2E was expected");
return -1;
}
- if (wpa_s->sme.sae.tmp &&
- (!wpa_s->sme.sae.tmp->h2e || wpa_s->sme.sae.tmp->pk) &&
+ if ((!wpa_s->sme.sae.h2e || wpa_s->sme.sae.pk) &&
status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
wpa_printf(MSG_DEBUG,
"SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected");
return -1;
}
- if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->pk &&
+ if (!wpa_s->sme.sae.pk &&
status_code == WLAN_STATUS_SAE_PK) {
wpa_printf(MSG_DEBUG,
"SAE: Unexpected use of status code for PK in SAE commit when PK was not expected");
@@ -1873,6 +1880,43 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
pfs_fail:
#endif /* CONFIG_DPP2 */
+ wpa_s->mscs_setup_done = false;
+ if (wpa_s->current_bss && wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len, *wpa_ie_len, max_ie_len;
+
+ if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_MSCS))
+ goto mscs_fail;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpa_ie_len = &wpa_s->sme.assoc_req_ie_len;
+ max_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((*wpa_ie_len + wpabuf_len(mscs_ie)) <= max_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE",
+ wpabuf_head(mscs_ie));
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_s->sme.assoc_req_ie + *wpa_ie_len,
+ wpabuf_head(mscs_ie), mscs_ie_len);
+ *wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
if (ssid && ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 411ce88..d0c9f0f 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -121,6 +121,15 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
os_free(wnmtfs_ie);
return -1;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->oci_freq_override_wnm_sleep) {
+ wpa_printf(MSG_INFO,
+ "TEST: Override OCI KDE frequency %d -> %d MHz",
+ ci.frequency,
+ wpa_s->oci_freq_override_wnm_sleep);
+ ci.frequency = wpa_s->oci_freq_override_wnm_sleep;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
oci_ie_len = OCV_OCI_EXTENDED_LEN;
oci_ie = os_zalloc(oci_ie_len);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6a2d2c3..f5b02f6 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3059,6 +3059,78 @@ static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_DPP */
+static int wpa_ctrl_command_bss(struct wpa_ctrl *ctrl, const char *cmd)
+{
+ char buf[512], *pos, *bssid, *freq, *level, *flags, *ssid;
+ size_t len;
+ int ret, id = -1;
+
+ if (!ctrl_conn)
+ return -1;
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
+ wpa_cli_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ return -2;
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ if (os_memcmp(buf, "FAIL", 4) == 0)
+ return -1;
+
+ pos = buf;
+ while (*pos != '\0') {
+ if (str_starts(pos, "id="))
+ id = atoi(pos + 3);
+ if (str_starts(pos, "bssid="))
+ bssid = pos + 6;
+ if (str_starts(pos, "freq="))
+ freq = pos + 5;
+ if (str_starts(pos, "level="))
+ level = pos + 6;
+ if (str_starts(pos, "flags="))
+ flags = pos + 6;
+ if (str_starts(pos, "ssid="))
+ ssid = pos + 5;
+
+ while (*pos != '\0' && *pos != '\n')
+ pos++;
+ *pos++ = '\0';
+ }
+ if (id != -1)
+ printf("%s\t%s\t%s\t%s\t%s\n", bssid, freq, level, flags, ssid);
+ return id;
+}
+
+
+static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[64];
+ int id = -1;
+ unsigned int mask;
+
+ printf("bssid / frequency / signal level / flags / ssid\n");
+
+ mask = WPA_BSS_MASK_ID | WPA_BSS_MASK_BSSID | WPA_BSS_MASK_FREQ |
+ WPA_BSS_MASK_LEVEL | WPA_BSS_MASK_FLAGS | WPA_BSS_MASK_SSID;
+ do {
+ if (id < 0)
+ os_snprintf(cmd, sizeof(cmd), "BSS FIRST MASK=0x%x",
+ mask);
+ else
+ os_snprintf(cmd, sizeof(cmd), "BSS NEXT-%d MASK=0x%x",
+ id, mask);
+ id = wpa_ctrl_command_bss(ctrl, cmd);
+ } while (id >= 0);
+
+ return 0;
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3718,6 +3790,8 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_none,
"*|<id> = remove DPP pkex information" },
#endif /* CONFIG_DPP */
+ { "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
+ "= list all BSS entries (scan results)" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f5a4c36..3d2c0a9 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1639,11 +1639,26 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (ssid->sae_password_id && sae_pwe != 3)
sae_pwe = 1;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
+#ifdef CONFIG_SAE_PK
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ ssid->sae_pk != SAE_PK_MODE_DISABLED &&
+ ((ssid->sae_password &&
+ sae_pk_valid_password(ssid->sae_password)) ||
+ (!ssid->sae_password && ssid->passphrase &&
+ sae_pk_valid_password(ssid->passphrase))));
+#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_TESTING_OPTIONS
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
wpa_s->ft_rsnxe_used);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL,
wpa_s->oci_freq_override_eapol);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_EAPOL_G2,
+ wpa_s->oci_freq_override_eapol_g2);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FT_ASSOC,
+ wpa_s->oci_freq_override_ft_assoc);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ wpa_s->oci_freq_override_fils_assoc);
#endif /* CONFIG_TESTING_OPTIONS */
/* Extended Key ID is only supported in infrastructure BSS so far */
@@ -1884,6 +1899,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+ break;
}
}
@@ -1891,7 +1909,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 10, i;
+ u8 len = 11, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -2745,9 +2763,9 @@ static u8 * wpas_populate_assoc_ies(
#ifdef CONFIG_MBO
const u8 *mbo_ie;
#endif
-#ifdef CONFIG_SAE
- int sae_pmksa_cached = 0;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ int pmksa_cached = 0;
+#endif /* CONFIG_SAE || CONFIG_FILS */
#ifdef CONFIG_FILS
const u8 *realm, *username, *rrk;
size_t realm_len, username_len, rrk_len;
@@ -2787,9 +2805,9 @@ static u8 * wpas_populate_assoc_ies(
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
-#ifdef CONFIG_SAE
- sae_pmksa_cached = 1;
-#endif /* CONFIG_SAE */
+#if defined(CONFIG_SAE) || defined(CONFIG_FILS)
+ pmksa_cached = 1;
+#endif /* CONFIG_SAE || CONFIG_FILS */
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -2888,6 +2906,10 @@ static u8 * wpas_populate_assoc_ies(
if (mask)
*mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
+ ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
+ pmksa_cached) {
+ algs = WPA_AUTH_ALG_FILS;
}
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
@@ -2904,7 +2926,7 @@ static u8 * wpas_populate_assoc_ies(
}
#ifdef CONFIG_SAE
- if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
+ if (pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
algs = WPA_AUTH_ALG_OPEN;
@@ -3170,6 +3192,40 @@ pfs_fail:
wpa_ie_len += wpa_s->rsnxe_len;
}
+ if (bss && wpa_s->robust_av.valid_config) {
+ struct wpabuf *mscs_ie;
+ size_t mscs_ie_len, buf_len;
+
+ if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS))
+ goto mscs_fail;
+
+ buf_len = 3 + /* MSCS descriptor IE header */
+ 1 + /* Request type */
+ 2 + /* User priority control */
+ 4 + /* Stream timeout */
+ 3 + /* TCLAS Mask IE header */
+ wpa_s->robust_av.frame_classifier_len;
+ mscs_ie = wpabuf_alloc(buf_len);
+ if (!mscs_ie) {
+ wpa_printf(MSG_INFO,
+ "MSCS: Failed to allocate MSCS IE");
+ goto mscs_fail;
+ }
+
+ wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
+ if ((wpa_ie_len + wpabuf_len(mscs_ie)) <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "MSCS IE",
+ wpabuf_head(mscs_ie));
+ mscs_ie_len = wpabuf_len(mscs_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(mscs_ie),
+ mscs_ie_len);
+ wpa_ie_len += mscs_ie_len;
+ }
+
+ wpabuf_free(mscs_ie);
+ }
+mscs_fail:
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -3484,6 +3540,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
wpa_s->rsnxe_len = 0;
+ wpa_s->mscs_setup_done = false;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
if (!wpa_ie) {
@@ -7918,7 +7975,7 @@ static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
ETH_ALEN);
num_bssid++;
}
- ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
+ ret = wpa_drv_set_bssid_tmp_disallow(wpa_s, num_bssid, bssids);
os_free(bssids);
return ret;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3b90567..1250834 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1472,6 +1472,58 @@ fast_reauth=1
# 2: do not allow PFS to be used
#dpp_pfs=0
+# Whether Beacon protection is enabled
+# This depends on management frame protection (ieee80211w) being enabled.
+#beacon_prot=0
+
+# OWE DH Group
+# 0: use default (19) first and then try all supported groups one by one if AP
+# rejects the selected group
+# 1-65535: DH Group to use for OWE
+# Groups 19 (NIST P-256), 20 (NIST P-384), and 21 (NIST P-521) are
+# currently supported.
+#owe_group=0
+
+# OWE-only mode (disable transition mode)
+# 0: enable transition mode (allow connection to either OWE or open BSS)
+# 1 = disable transition mode (allow connection only with OWE)
+#owe_only=0
+
+# OWE PTK derivation workaround
+# Initial OWE implementation used SHA256 when deriving the PTK for all
+# OWE groups. This was supposed to change to SHA384 for group 20 and
+# SHA512 for group 21. This parameter can be used to enable older
+# behavior mainly for testing purposes. There is no impact to group 19
+# behavior, but if enabled, this will make group 20 and 21 cases use
+# SHA256-based PTK derivation which will not work with the updated
+# OWE implementation on the AP side.
+#owe_ptk_workaround=0
+
+# Transition Disable indication
+# The AP can notify authenticated stations to disable transition mode
+# in their network profiles when the network has completed transition
+# steps, i.e., once sufficiently large number of APs in the ESS have
+# been updated to support the more secure alternative. When this
+# indication is used, the stations are expected to automatically
+# disable transition mode and less secure security options. This
+# includes use of WEP, TKIP (including use of TKIP as the group
+# cipher), and connections without PMF.
+# Bitmap bits:
+# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK
+# and only allow SAE to be used)
+# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK)
+# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF)
+# bit 3 (0x08): Enhanced Open (disable use of open network; require
+# OWE)
+
+# SAE-PK mode
+# 0: automatic SAE/SAE-PK selection based on password; enable
+# transition mode (allow SAE authentication without SAE-PK)
+# 1: SAE-PK only (disable transition mode; allow SAE authentication
+# only with SAE-PK)
+# 2: disable SAE-PK (allow SAE authentication only without SAE-PK)
+#sae_pk=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 28867f0..31a9b74 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -491,6 +491,17 @@ struct driver_signal_override {
int scan_level;
};
+struct robust_av_data {
+ u8 dialog_token;
+ enum scs_request_type request_type;
+ u8 up_bitmap;
+ u8 up_limit;
+ u32 stream_timeout;
+ u8 frame_classifier[48];
+ size_t frame_classifier_len;
+ bool valid_config;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -1152,6 +1163,10 @@ struct wpa_supplicant {
unsigned int oci_freq_override_eapol;
unsigned int oci_freq_override_saquery_req;
unsigned int oci_freq_override_saquery_resp;
+ unsigned int oci_freq_override_eapol_g2;
+ unsigned int oci_freq_override_ft_assoc;
+ unsigned int oci_freq_override_fils_assoc;
+ unsigned int oci_freq_override_wnm_sleep;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1277,10 +1292,10 @@ struct wpa_supplicant {
unsigned int dpp_resp_retry_time;
u8 dpp_last_ssid[SSID_MAX_LEN];
size_t dpp_last_ssid_len;
+ bool dpp_conf_backup_received;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
int dpp_pfs_fallback;
- struct wpabuf *dpp_reconfig_announcement;
struct wpabuf *dpp_presence_announcement;
struct dpp_bootstrap_info *dpp_chirp_bi;
int dpp_chirp_freq;
@@ -1291,6 +1306,7 @@ struct wpa_supplicant {
int dpp_chirp_listen;
struct wpa_ssid *dpp_reconfig_ssid;
int dpp_reconfig_ssid_id;
+ struct dpp_reconfig_id *dpp_reconfig_id;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
@@ -1310,6 +1326,8 @@ struct wpa_supplicant {
unsigned int multi_ap_ie:1;
unsigned int multi_ap_backhaul:1;
unsigned int multi_ap_fronthaul:1;
+ struct robust_av_data robust_av;
+ bool mscs_setup_done;
};
@@ -1523,6 +1541,9 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
struct channel_list_changed *info);
+int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *current_bss,
+ struct wpa_bss *seleceted);
/* eap_register.c */
int eap_register_methods(void);
@@ -1615,4 +1636,13 @@ int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
+int wpas_send_mscs_req(struct wpa_supplicant *wpa_s);
+void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
+ struct wpabuf *buf);
+void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf,
+ size_t len);
+void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const u8 *ies, size_t ies_len);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6bd271e..a9a66ba 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -575,7 +575,8 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid,
const u8 *fils_cache_id,
const u8 *pmk, size_t pmk_len,
- u32 pmk_lifetime, u8 pmk_reauth_threshold)
+ u32 pmk_lifetime, u8 pmk_reauth_threshold,
+ int akmp)
{
struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
@@ -583,9 +584,22 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
os_memset(&params, 0, sizeof(params));
ssid = wpas_get_network_ctx(wpa_s, network_ctx);
- if (ssid)
+ if (ssid) {
wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
MAC2STR(bssid), ssid->id);
+ if ((akmp == WPA_KEY_MGMT_FT_IEEE8021X ||
+ akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ !ssid->ft_eap_pmksa_caching) {
+ /* Since we will not be using PMKSA caching for FT-EAP
+ * within wpa_supplicant to avoid known interop issues
+ * with APs, do not add this PMKID to the driver either
+ * so that we won't be hitting those interop issues
+ * with driver-based RSNE generation. */
+ wpa_printf(MSG_DEBUG,
+ "FT: Do not add PMKID entry to the driver since FT-EAP PMKSA caching is not enabled in configuration");
+ return 0;
+ }
+ }
if (ssid && fils_cache_id) {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
@@ -1268,6 +1282,7 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
if (!ssid)
return;
+#ifdef CONFIG_SAE
if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
(ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
@@ -1279,6 +1294,24 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
changed = 1;
}
+ if ((bitmap & TRANSITION_DISABLE_SAE_PK) &&
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
+#ifdef CONFIG_SME
+ wpa_s->sme.sae.state == SAE_ACCEPTED &&
+ wpa_s->sme.sae.pk &&
+#endif /* CONFIG_SME */
+ (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ (ssid->sae_pk != SAE_PK_MODE_ONLY ||
+ ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
+ (ssid->group_cipher & WPA_CIPHER_TKIP))) {
+ wpa_printf(MSG_DEBUG,
+ "SAE-PK: SAE authentication without PK disabled based on AP notification");
+ disable_wpa_wpa2(ssid);
+ ssid->sae_pk = SAE_PK_MODE_ONLY;
+ changed = 1;
+ }
+#endif /* CONFIG_SAE */
+
if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
(ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X |