Revert "Revert "[wpa_supplicant] cumilative patch from commit 4b..."
Revert submission 28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Fixed the regression issue (ag/28389573)
Bug: 329004037
Reverted changes: /q/submissionid:28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Test: Turn ON/OFF SoftAp
Change-Id: Ie7ea1ee7f8b1311fce280907d37a2e321542f547
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index c0835ae..afcc04b 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -315,6 +315,7 @@
"src/common/sae.c",
"src/common/sae_pk.c",
"src/common/wpa_common.c",
+ "src/common/ptksa_cache.c",
"src/crypto/aes-ctr.c",
"src/crypto/aes-encblock.c",
"src/crypto/aes-siv.c",
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index baf3ad1..b667d82 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -139,6 +139,8 @@
OBJS += src/utils/bitfield.c
OBJS += src/utils/ip_addr.c
OBJS += src/utils/crc32.c
+OBJS += src/common/ptksa_cache.c
+OBJS += src/rsn_supp/pmksa_cache.c
OBJS += twt.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
@@ -379,7 +381,6 @@
ifndef CONFIG_NO_WPA
OBJS += src/rsn_supp/wpa.c
OBJS += src/rsn_supp/preauth.c
-OBJS += src/rsn_supp/pmksa_cache.c
OBJS += src/rsn_supp/wpa_ie.c
OBJS += src/common/wpa_common.c
NEED_AES=y
@@ -432,8 +433,8 @@
NEED_HMAC_SHA384_KDF=y
NEED_SHA256=y
NEED_SHA384=y
-OBJS += src/common/ptksa_cache.c
OBJS += src/pasn/pasn_initiator.c
+OBJS += src/pasn/pasn_common.c
OBJS += pasn_supplicant.c
endif
@@ -1846,8 +1847,9 @@
PASNOBJS += src/common/ptksa_cache.c
-ifndef CONFIG_NO_WPA
PASNOBJS += src/rsn_supp/pmksa_cache.c
+
+ifndef CONFIG_NO_WPA
PASNOBJS += src/rsn_supp/wpa_ie.c
endif
@@ -1933,6 +1935,7 @@
PASNOBJS += src/pasn/pasn_initiator.c
PASNOBJS += src/pasn/pasn_responder.c
+PASNOBJS += src/pasn/pasn_common.c
########################
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 93fc338..8bec178 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -112,6 +112,8 @@
OBJS += ../src/utils/bitfield.o
OBJS += ../src/utils/ip_addr.o
OBJS += ../src/utils/crc32.o
+OBJS += ../src/common/ptksa_cache.o
+OBJS += ../src/rsn_supp/pmksa_cache.o
OBJS += twt.o
OBJS_p = wpa_passphrase.o
OBJS_p += ../src/utils/common.o
@@ -374,7 +376,6 @@
ifndef CONFIG_NO_WPA
OBJS += ../src/rsn_supp/wpa.o
OBJS += ../src/rsn_supp/preauth.o
-OBJS += ../src/rsn_supp/pmksa_cache.o
OBJS += ../src/rsn_supp/wpa_ie.o
OBJS += ../src/common/wpa_common.o
NEED_AES=y
@@ -435,8 +436,8 @@
NEED_HMAC_SHA384_KDF=y
NEED_SHA256=y
NEED_SHA384=y
-OBJS += ../src/common/ptksa_cache.o
OBJS += ../src/pasn/pasn_initiator.o
+OBJS += ../src/pasn/pasn_common.o
OBJS += pasn_supplicant.o
endif
@@ -1187,6 +1188,10 @@
CFLAGS += -DCONFIG_TLSV12
endif
+ifdef CONFIG_RADIUS_TLS
+TLS_FUNCS=y
+endif
+
ifeq ($(CONFIG_TLS), wolfssl)
ifdef TLS_FUNCS
CFLAGS += -DWOLFSSL_DER_LOAD
@@ -1925,6 +1930,9 @@
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
OBJS_t += ../src/radius/radius.o
+ifdef CONFIG_RADIUS_TLS
+CFLAGS += -DCONFIG_RADIUS_TLS
+endif
OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o
@@ -2219,9 +2227,9 @@
endif
LIBPASNSO += ../src/common/ptksa_cache.c
+LIBPASNSO += ../src/rsn_supp/pmksa_cache.c
ifndef CONFIG_NO_WPA
-LIBPASNSO += ../src/rsn_supp/pmksa_cache.c
LIBPASNSO += ../src/rsn_supp/wpa_ie.c
endif
@@ -2316,6 +2324,7 @@
LIBPASNSO += ../src/pasn/pasn_initiator.c
LIBPASNSO += ../src/pasn/pasn_responder.c
+LIBPASNSO += ../src/pasn/pasn_common.c
libpasn.so: $(LIBPASNSO)
@$(E) " CC $@ ($^)"
diff --git a/wpa_supplicant/aidl/supplicant.cpp b/wpa_supplicant/aidl/supplicant.cpp
index 1589dd2..ae1943f 100644
--- a/wpa_supplicant/aidl/supplicant.cpp
+++ b/wpa_supplicant/aidl/supplicant.cpp
@@ -413,7 +413,7 @@
// Request the current scan results from the driver and update
// the local BSS list wpa_s->bss. This is to avoid a full scan
// while processing the connect request on newly created interface.
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, NULL);
}
// The supplicant core creates a corresponding aidl object via
// AidlManager when |wpa_supplicant_add_iface| is called.
@@ -472,7 +472,7 @@
// Request the current scan results from the driver and update
// the local BSS list wpa_s->bss. This is to avoid a full scan
// while processing the connect request on newly created interface.
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, NULL);
}
// The supplicant core creates a corresponding aidl object via
// AidlManager when |wpa_supplicant_add_iface| is called.
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 000914a..69a0e5e 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -440,9 +440,14 @@
}
}
- if (wpa_s->p2p_go_no_pri_sec_switch) {
+#ifdef CONFIG_P2P
+ if (ssid->p2p_group && wpa_s->p2p_go_no_pri_sec_switch) {
conf->no_pri_sec_switch = 1;
- } else if (conf->secondary_channel) {
+ return 0;
+ }
+#endif /* CONFIG_P2P */
+
+ if (conf->secondary_channel) {
struct wpa_supplicant *iface;
for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
@@ -868,7 +873,8 @@
static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
- int authorized, const u8 *p2p_dev_addr, const u8 *ip)
+ int authorized, const u8 *p2p_dev_addr,
+ const u8 *ip)
{
wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr, ip);
}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 22b694c..2890353 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -400,6 +400,11 @@
if (bss == wpa_s->ml_connect_probe_bss)
return 1;
+#ifdef CONFIG_WNM
+ if (bss == wpa_s->wnm_target_bss)
+ return 1;
+#endif /* CONFIG_WNM */
+
if (wpa_s->current_bss &&
(bss->ssid_len != wpa_s->current_bss->ssid_len ||
os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
@@ -414,10 +419,7 @@
if (!wpa_s->valid_links)
return 0;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
if (ether_addr_equal(bss->bssid, wpa_s->links[i].bssid))
return 1;
}
@@ -1513,9 +1515,6 @@
for (i = 0; i < count; i++) {
u8 bss_params;
- if (bss->n_mld_links >= MAX_NUM_MLD_LINKS)
- return;
-
if (end - pos < ap_info->tbtt_info_len)
break;
@@ -1523,6 +1522,8 @@
mld_params = pos + mld_params_offset;
link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK;
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ return;
if (*mld_params != mbssid_idx) {
wpa_printf(MSG_DEBUG,
@@ -1546,13 +1547,12 @@
wpa_s, neigh_bss->bssid)) {
struct mld_link *l;
- l = &bss->mld_links[bss->n_mld_links];
- l->link_id = link_id;
+ bss->valid_links |= BIT(link_id);
+ l = &bss->mld_links[link_id];
os_memcpy(l->bssid, pos + 1, ETH_ALEN);
l->freq = neigh_bss->freq;
l->disabled = mld_params[2] &
RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
- bss->n_mld_links++;
}
}
@@ -1678,15 +1678,15 @@
os_memcpy(ap_mld_addr, ml_basic_common_info->mld_addr,
ETH_ALEN);
- bss->n_mld_links = 0;
- l = &bss->mld_links[bss->n_mld_links];
link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK;
- l->link_id = link_id;
+
+ bss->mld_link_id = link_id;
+ seen = bss->valid_links = BIT(link_id);
+
+ l = &bss->mld_links[link_id];
os_memcpy(l->bssid, bss->bssid, ETH_ALEN);
l->freq = bss->freq;
- seen = BIT(link_id);
- bss->n_mld_links++;
/*
* The AP MLD ID in the RNR corresponds to the MBSSID index, see
@@ -1736,13 +1736,12 @@
}
}
- wpa_printf(MSG_DEBUG, "MLD: n_mld_links=%u (unresolved: 0x%04hx)",
- bss->n_mld_links, missing);
+ wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)",
+ bss->valid_links, missing);
- for (i = 0; i < bss->n_mld_links; i++) {
+ for_each_link(bss->valid_links, i) {
wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
- bss->mld_links[i].link_id,
- MAC2STR(bss->mld_links[i].bssid));
+ i, MAC2STR(bss->mld_links[i].bssid));
}
if (missing_links)
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index c06c20a..cc04963 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -126,11 +126,12 @@
size_t beacon_ie_len;
/** MLD address of the AP */
u8 mld_addr[ETH_ALEN];
+ /** Link ID of this affiliated AP of the AP MLD */
+ u8 mld_link_id;
/** An array of MLD links */
- u8 n_mld_links;
+ u16 valid_links;
struct mld_link {
- u8 link_id;
u8 bssid[ETH_ALEN];
int freq;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 8c0db68..c949bab 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -197,9 +197,10 @@
#endif /* NO_CONFIG_WRITE */
-static int wpa_config_parse_int(const struct parse_data *data,
- struct wpa_ssid *ssid,
- int line, const char *value)
+static int wpa_config_parse_int_impl(const struct parse_data *data,
+ struct wpa_ssid *ssid,
+ int line, const char *value,
+ bool check_range)
{
int val, *dst;
char *end;
@@ -212,31 +213,46 @@
return -1;
}
+ if (check_range && val < (long) data->param3) {
+ wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+ "min_value=%ld)", line, data->name, val,
+ (long) data->param3);
+ return -1;
+ }
+
+ if (check_range && val > (long) data->param4) {
+ wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+ "max_value=%ld)", line, data->name, val,
+ (long) data->param4);
+ return -1;
+ }
+
if (*dst == val)
return 1;
+
*dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
- if (data->param3 && *dst < (long) data->param3) {
- wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
- "min_value=%ld)", line, data->name, *dst,
- (long) data->param3);
- *dst = (long) data->param3;
- return -1;
- }
-
- if (data->param4 && *dst > (long) data->param4) {
- wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
- "max_value=%ld)", line, data->name, *dst,
- (long) data->param4);
- *dst = (long) data->param4;
- return -1;
- }
-
return 0;
}
+static int wpa_config_parse_int(const struct parse_data *data,
+ struct wpa_ssid *ssid,
+ int line, const char *value)
+{
+ return wpa_config_parse_int_impl(data, ssid, line, value, false);
+}
+
+
+static int wpa_config_parse_int_range(const struct parse_data *data,
+ struct wpa_ssid *ssid,
+ int line, const char *value)
+{
+ return wpa_config_parse_int_impl(data, ssid, line, value, true);
+}
+
+
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_int(const struct parse_data *data,
struct wpa_ssid *ssid)
@@ -2457,7 +2473,14 @@
#define INTe(f, m) _INTe(f, m), NULL, NULL, 0
/* INT_RANGE: Define an integer variable with allowed value range */
-#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
+#ifdef NO_CONFIG_WRITE
+#define INT_RANGE(f, min, max) #f, wpa_config_parse_int_range, OFFSET(f), \
+ (void *) 0, (void *) (min), (void *) (max), 0
+#else /* NO_CONFIG_WRITE */
+#define INT_RANGE(f, min, max) #f, wpa_config_parse_int_range, \
+ wpa_config_write_int, OFFSET(f), \
+ (void *) 0, (void *) (min), (void *) (max), 0
+#endif /* NO_CONFIG_WRITE */
/* FUNC: Define a configuration variable that uses a custom function for
* parsing and writing the value. */
@@ -2652,7 +2675,7 @@
#endif /* CONFIG_P2P */
#ifdef CONFIG_HT_OVERRIDES
{ INT_RANGE(disable_ht, 0, 1) },
- { INT_RANGE(disable_ht40, -1, 1) },
+ { INT_RANGE(disable_ht40, 0, 1) },
{ INT_RANGE(disable_sgi, 0, 1) },
{ INT_RANGE(disable_ldpc, 0, 1) },
{ INT_RANGE(ht40_intolerant, 0, 1) },
@@ -2725,6 +2748,8 @@
{ INT_RANGE(owe_ptk_workaround, 0, 1) },
{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
{ INT_RANGE(ft_eap_pmksa_caching, 0, 1) },
+ { INT_RANGE(multi_ap_profile, MULTI_AP_PROFILE_1,
+ MULTI_AP_PROFILE_MAX) },
{ INT_RANGE(beacon_prot, 0, 1) },
{ INT_RANGE(transition_disable, 0, 255) },
{ INT_RANGE(sae_pk, 0, 2) },
@@ -4743,9 +4768,10 @@
};
-static int wpa_global_config_parse_int(const struct global_parse_data *data,
- struct wpa_config *config, int line,
- const char *pos)
+static int
+wpa_global_config_parse_int_impl(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos, bool check_range)
{
int val, *dst;
char *end;
@@ -4758,31 +4784,47 @@
line, pos);
return -1;
}
+
+ if (check_range && val < (long) data->param2) {
+ wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+ "min_value=%ld)", line, data->name, val,
+ (long) data->param2);
+ return -1;
+ }
+
+ if (check_range && val > (long) data->param3) {
+ wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+ "max_value=%ld)", line, data->name, val,
+ (long) data->param3);
+ return -1;
+ }
+
same = *dst == val;
*dst = val;
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
- if (data->param2 && *dst < (long) data->param2) {
- wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
- "min_value=%ld)", line, data->name, *dst,
- (long) data->param2);
- *dst = (long) data->param2;
- return -1;
- }
-
- if (data->param3 && *dst > (long) data->param3) {
- wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
- "max_value=%ld)", line, data->name, *dst,
- (long) data->param3);
- *dst = (long) data->param3;
- return -1;
- }
-
return same;
}
+static int wpa_global_config_parse_int(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ return wpa_global_config_parse_int_impl(data, config, line, pos, false);
+}
+
+
+static int
+wpa_global_config_parse_int_range(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ return wpa_global_config_parse_int_impl(data, config, line, pos, true);
+}
+
+
static int wpa_global_config_parse_str(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
@@ -5346,7 +5388,8 @@
#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL
#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f)
#define INT(f) _INT(f), NULL, NULL
-#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
+#define INT_RANGE(f, min, max) #f, wpa_global_config_parse_int_range, \
+ wpa_config_get_int, OFFSET(f), (void *) min, (void *) max
#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
#define STR(f) _STR(f), NULL, NULL
#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 71a64b1..414ed22 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -850,6 +850,7 @@
INT(owe_ptk_workaround);
INT(multi_ap_backhaul_sta);
INT(ft_eap_pmksa_caching);
+ INT(multi_ap_profile);
INT(beacon_prot);
INT(transition_disable);
INT(sae_pk);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 785acc3..2043a80 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -1187,6 +1187,11 @@
int ft_eap_pmksa_caching;
/**
+ * multi_ap_profile - Supported Multi-AP profile
+ */
+ int multi_ap_profile;
+
+ /**
* beacon_prot - Whether Beacon protection is enabled
*
* This depends on management frame protection (ieee80211w) being
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 500f4d1..d0fda4c 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -902,9 +902,20 @@
wpa_config_process_global(wpa_s->conf, cmd, -1);
}
} else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
- wpas_mbo_update_cell_capa(wpa_s, atoi(value));
+ int val = atoi(value);
+
+ if (val < MBO_CELL_CAPA_AVAILABLE ||
+ val > MBO_CELL_CAPA_NOT_SUPPORTED)
+ return -1;
+
+ wpas_mbo_update_cell_capa(wpa_s, val);
} else if (os_strcasecmp(cmd, "oce") == 0) {
- wpa_s->conf->oce = atoi(value);
+ int val = atoi(value);
+
+ if (val < 0 || val > 3)
+ return -1;
+
+ wpa_s->conf->oce = val;
if (wpa_s->conf->oce) {
if ((wpa_s->conf->oce & OCE_STA) &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
@@ -8850,6 +8861,8 @@
wpa_s->next_ssid = NULL;
+ wnm_btm_reset(wpa_s);
+
#ifdef CONFIG_INTERWORKING
#ifdef CONFIG_HS20
hs20_cancel_fetch_osu(wpa_s);
@@ -11995,10 +12008,7 @@
pos = buf;
end = buf + buflen;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(mlo_si.valid_links & BIT(i)))
- continue;
-
+ for_each_link(mlo_si.valid_links, i) {
ret = os_snprintf(pos, end - pos,
"LINK_ID=%d\nRSSI=%d\nLINKSPEED=%lu\n"
"NOISE=%d\nFREQUENCY=%u\n",
@@ -12070,10 +12080,7 @@
pos = buf;
end = buf + buflen;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
ret = os_snprintf(pos, end - pos, "link_id=%d\nfreq=%u\n"
"ap_link_addr=" MACSTR
"\nsta_link_addr=" MACSTR "\n",
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index fdf7b12..27003eb 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -706,6 +706,59 @@
}
+#define UINT16_ARRAY_CHUNK_SIZE 18
+#define UINT16_ARRAY_ITEM_SIZE (sizeof(dbus_uint16_t))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_uint16_array(
+ DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+ dbus_uint32_t count = 0;
+ dbus_uint16_t *buffer, *nbuffer;
+
+ entry->uint16array_value = NULL;
+ entry->array_type = DBUS_TYPE_UINT16;
+
+ buffer = os_calloc(UINT16_ARRAY_CHUNK_SIZE, UINT16_ARRAY_ITEM_SIZE);
+ if (!buffer)
+ return FALSE;
+
+ entry->array_len = 0;
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_UINT16) {
+ dbus_uint16_t value;
+
+ if ((count % UINT16_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
+ nbuffer = os_realloc_array(
+ buffer, count + UINT16_ARRAY_CHUNK_SIZE,
+ UINT16_ARRAY_ITEM_SIZE);
+ if (!nbuffer) {
+ os_free(buffer);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to retrieve the uint16 array",
+ __func__);
+ return FALSE;
+ }
+ buffer = nbuffer;
+ }
+
+ dbus_message_iter_get_basic(iter, &value);
+ buffer[count] = value;
+ entry->array_len = ++count;
+ dbus_message_iter_next(iter);
+ }
+ entry->uint16array_value = buffer;
+ wpa_hexdump_key(MSG_MSGDUMP, "dbus: uint16 array contents",
+ entry->bytearray_value, entry->array_len);
+
+ /* Zero-length arrays are valid. */
+ if (entry->array_len == 0) {
+ os_free(entry->uint16array_value);
+ entry->uint16array_value = NULL;
+ }
+
+ return TRUE;
+}
+
+
#define STR_ARRAY_CHUNK_SIZE 8
#define STR_ARRAY_ITEM_SIZE (sizeof(char *))
@@ -873,6 +926,10 @@
success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
entry);
break;
+ case DBUS_TYPE_UINT16:
+ success = _wpa_dbus_dict_entry_get_uint16_array(&iter_array,
+ entry);
+ break;
case DBUS_TYPE_STRING:
success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
array_type,
@@ -1081,6 +1138,9 @@
case DBUS_TYPE_BYTE:
os_free(entry->bytearray_value);
break;
+ case DBUS_TYPE_UINT16:
+ os_free(entry->uint16array_value);
+ break;
case DBUS_TYPE_STRING:
if (!entry->strarray_value)
break;
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index cc9e26f..1d33689 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -139,6 +139,7 @@
dbus_uint64_t uint64_value;
double double_value;
char *bytearray_value;
+ dbus_uint16_t *uint16array_value;
char **strarray_value;
struct wpabuf **binarray_value;
};
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 00b38ed..8bd6a9a 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1023,6 +1023,40 @@
dbus_message_unref(msg);
}
+
+void wpas_dbus_signal_anqp_query_done(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *result)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char addr[WPAS_DBUS_OBJECT_PATH_MAX], *bssid;
+
+ os_snprintf(addr, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(dst));
+ bssid = addr;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "ANQPQueryDone");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bssid) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &result))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
#endif /* CONFIG_INTERWORKING */
@@ -2439,6 +2473,9 @@
case WPAS_DBUS_BSS_PROP_AGE:
prop = "Age";
break;
+ case WPAS_DBUS_BSS_PROP_ANQP:
+ prop = "ANQP";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -2977,6 +3014,11 @@
NULL,
NULL
},
+ {"ANQP", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+ wpas_dbus_getter_bss_anqp,
+ NULL,
+ NULL,
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -3716,6 +3758,13 @@
END_ARGS
}
},
+ {"ANQPGet", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_anqp_get,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ },
+ },
#endif /* CONFIG_INTERWORKING */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -4303,6 +4352,13 @@
END_ARGS
}
},
+ {"ANQPQueryDone", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "addr", "s", ARG_OUT },
+ { "result", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
{ "HS20TermsAndConditions", WPAS_DBUS_NEW_IFACE_INTERFACE,
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index b653f10..952bb42 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -53,6 +53,7 @@
WPAS_DBUS_BSS_PROP_WPS,
WPAS_DBUS_BSS_PROP_IES,
WPAS_DBUS_BSS_PROP_AGE,
+ WPAS_DBUS_BSS_PROP_ANQP,
};
enum wpas_dbus_sta_prop {
@@ -279,6 +280,8 @@
int bh, int bss_load,
int conn_capab);
void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s);
+void wpas_dbus_signal_anqp_query_done(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *result);
void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s,
const char *url);
@@ -653,6 +656,12 @@
}
static inline
+void wpas_dbus_signal_anqp_query_done(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *result)
+{
+}
+
+static inline
void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s,
const char *url)
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 6ad49a1..3897d98 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1957,6 +1957,7 @@
#ifdef CONFIG_INTERWORKING
+
DBusMessage *
wpas_dbus_handler_interworking_select(DBusMessage *message,
struct wpa_supplicant *wpa_s)
@@ -1977,6 +1978,111 @@
return reply;
}
+
+
+DBusMessage *
+wpas_dbus_handler_anqp_get(DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ struct wpa_dbus_dict_entry entry;
+ int ret;
+ u8 dst_addr[ETH_ALEN];
+ bool is_addr_present = false;
+ unsigned int freq = 0;
+#define MAX_ANQP_INFO_ID 100 /* Max info ID count from CLI implementation */
+ u16 id[MAX_ANQP_INFO_ID];
+ size_t num_id = 0;
+ u32 subtypes = 0;
+ u32 mbo_subtypes = 0;
+ size_t i;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (os_strcmp(entry.key, "addr") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (hwaddr_aton(entry.str_value, dst_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Invalid address '%s'",
+ __func__, entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ return wpas_dbus_error_invalid_args(
+ message, "invalid address");
+ }
+
+ is_addr_present = true;
+ } else if (os_strcmp(entry.key, "freq") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ freq = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "ids") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_UINT16) {
+ for (i = 0; i < entry.array_len &&
+ num_id < MAX_ANQP_INFO_ID; i++) {
+ id[num_id] = entry.uint16array_value[i];
+ num_id++;
+ }
+ } else if (os_strcmp(entry.key, "hs20_ids") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ for (i = 0; i < entry.array_len; i++) {
+ int num = entry.bytearray_value[i];
+
+ if (num <= 0 || num > 31) {
+ wpa_dbus_dict_entry_clear(&entry);
+ return wpas_dbus_error_invalid_args(
+ message,
+ "invalid HS20 ANQP id");
+ }
+ subtypes |= BIT(num);
+ }
+ } else if (os_strcmp(entry.key, "mbo_ids") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ for (i = 0; i < entry.array_len; i++) {
+ int num = entry.bytearray_value[i];
+
+ if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE) {
+ wpa_dbus_dict_entry_clear(&entry);
+ return wpas_dbus_error_invalid_args(
+ message, "invalid MBO ANQP id");
+ }
+ mbo_subtypes |= BIT(num);
+ }
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ return wpas_dbus_error_invalid_args(
+ message, "unsupported parameter");
+ }
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (!is_addr_present) {
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: address not provided", __func__);
+ return wpas_dbus_error_invalid_args(message,
+ "address not provided");
+ }
+
+ ret = anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes,
+ mbo_subtypes);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s[dbus]: failed to send ANQP request",
+ __func__);
+ return wpas_dbus_error_unknown_error(
+ message, "error sending ANQP request");
+ }
+
+ return NULL;
+}
+
#endif /* CONFIG_INTERWORKING */
@@ -5652,6 +5758,177 @@
/**
+ * wpas_dbus_getter_bss_anqp - Return all the ANQP fields of a BSS
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "ANQP" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_anqp(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ DBusMessageIter iter_dict, variant_iter;
+ struct bss_handler_args *args = user_data;
+ struct wpa_bss *bss;
+ struct wpa_bss_anqp *anqp;
+ struct wpa_bss_anqp_elem *elem;
+
+ bss = get_bss_helper(args, error, __func__);
+ if (!bss)
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ goto nomem;
+
+ anqp = bss->anqp;
+ if (anqp) {
+#ifdef CONFIG_INTERWORKING
+ if (anqp->capability_list &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "CapabilityList",
+ wpabuf_head(anqp->capability_list),
+ wpabuf_len(anqp->capability_list)))
+ goto nomem;
+ if (anqp->venue_name &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "VenueName",
+ wpabuf_head(anqp->venue_name),
+ wpabuf_len(anqp->venue_name)))
+ goto nomem;
+ if (anqp->network_auth_type &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "NetworkAuthType",
+ wpabuf_head(anqp->network_auth_type),
+ wpabuf_len(anqp->network_auth_type)))
+ goto nomem;
+ if (anqp->roaming_consortium &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "RoamingConsortium",
+ wpabuf_head(anqp->roaming_consortium),
+ wpabuf_len(anqp->roaming_consortium)))
+ goto nomem;
+ if (anqp->ip_addr_type_availability &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "IPAddrTypeAvailability",
+ wpabuf_head(anqp->ip_addr_type_availability),
+ wpabuf_len(anqp->ip_addr_type_availability)))
+ goto nomem;
+ if (anqp->nai_realm &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "NAIRealm",
+ wpabuf_head(anqp->nai_realm),
+ wpabuf_len(anqp->nai_realm)))
+ goto nomem;
+ if (anqp->anqp_3gpp &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "3GPP",
+ wpabuf_head(anqp->anqp_3gpp),
+ wpabuf_len(anqp->anqp_3gpp)))
+ goto nomem;
+ if (anqp->domain_name &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "DomainName",
+ wpabuf_head(anqp->domain_name),
+ wpabuf_len(anqp->domain_name)))
+ goto nomem;
+ if (anqp->fils_realm_info &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "FilsRealmInfo",
+ wpabuf_head(anqp->fils_realm_info),
+ wpabuf_len(anqp->fils_realm_info)))
+ goto nomem;
+
+#ifdef CONFIG_HS20
+ if (anqp->hs20_capability_list &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20CapabilityList",
+ wpabuf_head(anqp->hs20_capability_list),
+ wpabuf_len(anqp->hs20_capability_list)))
+ goto nomem;
+ if (anqp->hs20_operator_friendly_name &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20OperatorFriendlyName",
+ wpabuf_head(anqp->hs20_operator_friendly_name),
+ wpabuf_len(anqp->hs20_operator_friendly_name)))
+ goto nomem;
+ if (anqp->hs20_wan_metrics &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20WanMetrics",
+ wpabuf_head(anqp->hs20_wan_metrics),
+ wpabuf_len(anqp->hs20_wan_metrics)))
+ goto nomem;
+ if (anqp->hs20_connection_capability &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20ConnectionCapability",
+ wpabuf_head(anqp->hs20_connection_capability),
+ wpabuf_len(anqp->hs20_connection_capability)))
+ goto nomem;
+ if (anqp->hs20_operating_class &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20OperatingClass",
+ wpabuf_head(anqp->hs20_operating_class),
+ wpabuf_len(anqp->hs20_operating_class)))
+ goto nomem;
+ if (anqp->hs20_osu_providers_list &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20OSUProvidersList",
+ wpabuf_head(anqp->hs20_osu_providers_list),
+ wpabuf_len(anqp->hs20_osu_providers_list)))
+ goto nomem;
+ if (anqp->hs20_operator_icon_metadata &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20OperatorIconMetadata",
+ wpabuf_head(anqp->hs20_operator_icon_metadata),
+ wpabuf_len(anqp->hs20_operator_icon_metadata)))
+ goto nomem;
+ if (anqp->hs20_osu_providers_nai_list &&
+ !wpa_dbus_dict_append_byte_array(
+ &iter_dict, "HS20OSUProvidersNAIList",
+ wpabuf_head(anqp->hs20_osu_providers_nai_list),
+ wpabuf_len(anqp->hs20_osu_providers_nai_list)))
+ goto nomem;
+#endif /* CONFIG_HS20 */
+
+ dl_list_for_each(elem, &anqp->anqp_elems,
+ struct wpa_bss_anqp_elem, list) {
+ char title[32];
+
+ os_snprintf(title, sizeof(title), "anqp[%u]",
+ elem->infoid);
+ if (!wpa_dbus_dict_append_byte_array(
+ &iter_dict, title,
+ wpabuf_head(elem->payload),
+ wpabuf_len(elem->payload)))
+ goto nomem;
+
+ os_snprintf(title, sizeof(title),
+ "protected-anqp-info[%u]", elem->infoid);
+ if (!wpa_dbus_dict_append_bool(
+ &iter_dict, title,
+ elem->protected_response))
+ goto nomem;
+ }
+#endif /* CONFIG_INTERWORKING */
+ }
+
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
+ goto nomem;
+
+ return TRUE;
+
+nomem:
+ dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+}
+
+
+/**
* wpas_dbus_getter_enabled - Check whether network is enabled or disabled
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 97fa337..acd6af7 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -157,6 +157,9 @@
wpas_dbus_handler_interworking_select(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage *
+wpas_dbus_handler_anqp_get(DBusMessage *message, struct wpa_supplicant *wpa_s);
+
DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
DECLARE_ACCESSOR(wpas_dbus_getter_state);
DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
@@ -216,6 +219,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_age);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_anqp);
DECLARE_ACCESSOR(wpas_dbus_getter_enabled);
DECLARE_ACCESSOR(wpas_dbus_setter_enabled);
DECLARE_ACCESSOR(wpas_dbus_getter_network_properties);
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 801e698..e223450 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -238,6 +238,12 @@
wait_time = wpa_s->dpp_resp_retry_time;
else
wait_time = 1000;
+ if (wpa_s->dpp_tx_chan_change) {
+ wpa_s->dpp_tx_chan_change = false;
+ if (wait_time > 100)
+ wait_time = 100;
+ }
+
wpa_printf(MSG_DEBUG,
"DPP: Schedule retransmission of Authentication Response frame in %u ms",
wait_time);
@@ -487,6 +493,21 @@
}
+static void wpas_dpp_neg_freq_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!wpa_s->dpp_listen_on_tx_expire || !auth || !auth->neg_freq)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start listen on neg_freq %u MHz based on timeout for TX wait expiration",
+ auth->neg_freq);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq);
+}
+
+
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid,
@@ -605,7 +626,9 @@
wpa_s->dpp_auth->curr_freq,
wpa_s->dpp_auth->neg_freq);
offchannel_send_action_done(wpa_s);
- wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq);
+ wpa_s->dpp_listen_on_tx_expire = true;
+ eloop_register_timeout(0, 100000, wpas_dpp_neg_freq_timeout,
+ wpa_s, NULL);
}
if (wpa_s->dpp_auth_ok_on_ack)
@@ -1035,6 +1058,8 @@
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = lwork->freq;
wpa_drv_dpp_listen(wpa_s, true);
+ wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
+ wpa_s->dpp_tx_chan_change = false;
}
@@ -1134,11 +1159,58 @@
}
+static void wpas_dpp_tx_auth_resp(struct wpa_supplicant *wpa_s)
+{
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth)
+ return;
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(auth->peer_mac_addr), auth->curr_freq,
+ DPP_PA_AUTHENTICATION_RESP);
+ offchannel_send_action(wpa_s, auth->curr_freq,
+ auth->peer_mac_addr, wpa_s->own_addr, broadcast,
+ wpabuf_head(auth->resp_msg),
+ wpabuf_len(auth->resp_msg),
+ 500, wpas_dpp_tx_status, 0);
+}
+
+
+static void wpas_dpp_tx_auth_resp_roc_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !wpa_s->dpp_tx_auth_resp_on_roc_stop)
+ return;
+
+ wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
+ wpa_s->dpp_tx_chan_change = true;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send postponed Authentication Response on remain-on-channel termination timeout");
+ wpas_dpp_tx_auth_resp(wpa_s);
+}
+
+
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
+ wpa_printf(MSG_DEBUG, "DPP: Remain on channel cancel for %u MHz", freq);
wpas_dpp_listen_work_done(wpa_s);
+ if (wpa_s->dpp_auth && wpa_s->dpp_tx_auth_resp_on_roc_stop) {
+ eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout,
+ wpa_s, NULL);
+ wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
+ wpa_s->dpp_tx_chan_change = true;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send postponed Authentication Response on remain-on-channel termination");
+ wpas_dpp_tx_auth_resp(wpa_s);
+ return;
+ }
+
if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) {
unsigned int new_freq;
@@ -1256,17 +1328,17 @@
wpa_printf(MSG_DEBUG,
"DPP: Stop listen on %u MHz to allow response on the request %u MHz",
wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq);
+ wpa_s->dpp_tx_auth_resp_on_roc_stop = true;
+ eloop_register_timeout(0, 100000,
+ wpas_dpp_tx_auth_resp_roc_timeout,
+ wpa_s, NULL);
wpas_dpp_listen_stop(wpa_s);
+ return;
}
+ wpa_s->dpp_tx_auth_resp_on_roc_stop = false;
+ wpa_s->dpp_tx_chan_change = false;
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
- MAC2STR(src), wpa_s->dpp_auth->curr_freq,
- DPP_PA_AUTHENTICATION_RESP);
- offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq,
- src, wpa_s->own_addr, broadcast,
- wpabuf_head(wpa_s->dpp_auth->resp_msg),
- wpabuf_len(wpa_s->dpp_auth->resp_msg),
- 500, wpas_dpp_tx_status, 0);
+ wpas_dpp_tx_auth_resp(wpa_s);
}
@@ -1275,6 +1347,15 @@
struct dpp_authentication *auth = wpa_s->dpp_auth;
int freq;
+ if (wpa_s->dpp_listen_on_tx_expire && auth && auth->neg_freq) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Start listen on neg_freq %u MHz based on TX wait expiration on the previous channel",
+ auth->neg_freq);
+ eloop_cancel_timeout(wpas_dpp_neg_freq_timeout, wpa_s, NULL);
+ wpas_dpp_listen_start(wpa_s, auth->neg_freq);
+ return;
+ }
+
if (!wpa_s->dpp_gas_server || !auth) {
if (auth && auth->waiting_auth_resp &&
eloop_is_timeout_registered(wpas_dpp_drv_wait_timeout,
@@ -4816,6 +4897,8 @@
eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_gas_client_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_neg_freq_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout,
@@ -5627,6 +5710,7 @@
eloop_register_timeout(100, 0, wpas_dpp_push_button_expire,
wpa_s, NULL);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS "started");
return 0;
}
@@ -5688,6 +5772,7 @@
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->scan_res_handler = wpas_dpp_pb_scan_res_handler;
wpa_supplicant_req_scan(wpa_s, 0, 0);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS "started");
return 0;
}
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 9a4c235..d01b52b 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -128,7 +128,7 @@
}
struct wpa_scan_results *
-wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s);
+wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, const u8 *bssid);
static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
{
@@ -342,14 +342,6 @@
return -1;
}
-static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
- struct wpa_driver_ap_params *params)
-{
- if (wpa_s->driver->set_ap)
- return wpa_s->driver->set_ap(wpa_s->drv_priv, params);
- return -1;
-}
-
static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s,
struct hostapd_sta_add_params *params)
{
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 9641062..95953de 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -670,6 +670,10 @@
wpa_s->eapol = NULL;
if (e->radius_conf && e->radius_conf->auth_server) {
os_free(e->radius_conf->auth_server->shared_secret);
+ os_free(e->radius_conf->auth_server->ca_cert);
+ os_free(e->radius_conf->auth_server->client_cert);
+ os_free(e->radius_conf->auth_server->private_key);
+ os_free(e->radius_conf->auth_server->private_key_passwd);
os_free(e->radius_conf->auth_server);
}
os_free(e->radius_conf);
@@ -1007,7 +1011,10 @@
static void wpa_init_conf(struct eapol_test_data *e,
struct wpa_supplicant *wpa_s, const char *authsrv,
- int port, const char *secret,
+ int port, bool tls, const char *secret,
+ const char *ca_cert, const char *client_cert,
+ const char *private_key,
+ const char *private_key_passwd,
const char *cli_addr, const char *ifname)
{
struct hostapd_radius_server *as;
@@ -1045,8 +1052,17 @@
}
#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
as->port = port;
+ as->tls = tls;
as->shared_secret = (u8 *) os_strdup(secret);
as->shared_secret_len = os_strlen(secret);
+ if (ca_cert)
+ as->ca_cert = os_strdup(ca_cert);
+ if (client_cert)
+ as->client_cert = os_strdup(client_cert);
+ if (private_key)
+ as->private_key = os_strdup(private_key);
+ if (private_key_passwd)
+ as->private_key_passwd = os_strdup(private_key_passwd);
e->radius_conf->auth_server = as;
e->radius_conf->auth_servers = as;
e->radius_conf->msg_dumps = 1;
@@ -1256,11 +1272,16 @@
{
printf("usage:\n"
"eapol_test [-enWSv] -c<conf> [-a<AS IP>] [-p<AS port>] "
- "[-s<AS secret>]\\\n"
+ "[-s<AS secret>] \\\n"
+ " [-X<RADIUS protocol> \\\n"
" [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
" [-M<client MAC address>] [-o<server cert file] \\\n"
" [-N<attr spec>] [-R<PC/SC reader>] "
"[-P<PC/SC PIN>] \\\n"
+#ifdef CONFIG_RADIUS_TLS
+ " [-j<CA cert>] [-J<client cert>] \\\n"
+ "[-k<private key] [-K<private key passwd>] \\\n"
+#endif /* CONFIG_RADIUS_TLS */
" [-A<client IP>] [-i<ifname>] [-T<ctrl_iface>]\n"
"eapol_test scard\n"
"eapol_test sim <PIN> <num triplets> [debug]\n"
@@ -1269,10 +1290,11 @@
" -c<conf> = configuration file\n"
" -a<AS IP> = IP address of the authentication server, "
"default 127.0.0.1\n"
- " -p<AS port> = UDP port of the authentication server, "
- "default 1812\n"
- " -s<AS secret> = shared secret with the authentication "
- "server, default 'radius'\n"
+ " -p<AS port> = Port of the authentication server,\n"
+ " default 1812 for RADIUS/UDP and 2083 for RADIUS/TLS\n"
+ " -s<AS secret> = shared secret with the authentication server,\n"
+ " default 'radius' for RADIUS/UDP and 'radsec' for RADIUS/TLS\n"
+ " -X<RADIUS protocol> = RADIUS protocol to use: UDP (default) or TLS\n"
" -A<client IP> = IP address of the client, default: select "
"automatically\n"
" -r<count> = number of re-authentications\n"
@@ -1310,8 +1332,11 @@
struct wpa_supplicant wpa_s;
int c, ret = 1, wait_for_monitor = 0, save_config = 0;
char *as_addr = "127.0.0.1";
- int as_port = 1812;
- char *as_secret = "radius";
+ int as_port = -1;
+ char *as_secret = NULL;
+ char *ca_cert = NULL, *client_cert = NULL;
+ char *private_key = NULL, *private_key_passwd = NULL;
+ bool tls = false;
char *cli_addr = NULL;
char *conf = NULL;
int timeout = 30;
@@ -1334,7 +1359,8 @@
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW");
+ c = getopt(argc, argv,
+ "a:A:c:C:ei:j:J:k:K:M:nN:o:p:P:r:R:s:St:T:vWX:");
if (c < 0)
break;
switch (c) {
@@ -1356,6 +1382,20 @@
case 'i':
ifname = optarg;
break;
+#ifdef CONFIG_RADIUS_TLS
+ case 'j':
+ ca_cert = optarg;
+ break;
+ case 'J':
+ client_cert = optarg;
+ break;
+ case 'k':
+ private_key = optarg;
+ break;
+ case 'K':
+ private_key_passwd = optarg;
+ break;
+#endif /* CONFIG_RADIUS_TLS */
case 'M':
if (hwaddr_aton(optarg, eapol_test.own_addr)) {
usage();
@@ -1406,6 +1446,16 @@
case 'W':
wait_for_monitor++;
break;
+ case 'X':
+ if (os_strcmp(optarg, "UDP") == 0) {
+ tls = false;
+ } else if (os_strcmp(optarg, "TLS") == 0) {
+ tls = true;
+ } else {
+ usage();
+ return -1;
+ }
+ break;
case 'N':
p1 = os_zalloc(sizeof(*p1));
if (p1 == NULL)
@@ -1440,6 +1490,11 @@
}
}
+ if (!as_secret)
+ as_secret = tls ? "radsec" : "radius";
+ if (as_port < 0)
+ as_port = tls ? 2083 : 1812;
+
if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
return scard_test(&eapol_test);
}
@@ -1489,7 +1544,8 @@
wpa_s.conf->pcsc_reader = os_strdup(eapol_test.pcsc_reader);
}
- wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
+ wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, tls, as_secret,
+ ca_cert, client_cert, private_key, private_key_passwd,
cli_addr, ifname);
wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
if (wpa_s.ctrl_iface == NULL) {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index bc45579..ff18543 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -164,7 +164,7 @@
struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
if (!bss) {
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, bssid);
/* Get the BSS from the new scan results */
bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
@@ -183,7 +183,7 @@
struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
if (!bss) {
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, bssid);
bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
}
@@ -1156,19 +1156,18 @@
static bool wpas_valid_ml_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
-
{
u16 removed_links;
if (wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL, NULL, NULL))
return true;
- if (bss->n_mld_links == 0)
+ if (!bss->valid_links)
return true;
/* Check if the current BSS is going to be removed */
removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss);
- if (BIT(bss->mld_links[0].link_id) & removed_links)
+ if (BIT(bss->mld_link_id) & removed_links)
return false;
return true;
@@ -1697,13 +1696,11 @@
return NULL;
}
-#ifdef CONFIG_WNM
if (wnm_is_bss_excluded(wpa_s, bss)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID excluded");
return NULL;
}
-#endif /* CONFIG_WNM */
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
@@ -1809,10 +1806,12 @@
break;
}
- if (selected == NULL && wpa_s->bssid_ignore &&
+ if (!selected &&
+ (wpa_s->bssid_ignore || wnm_active_bss_trans_mgmt(wpa_s)) &&
!wpa_s->countermeasures) {
wpa_dbg(wpa_s, MSG_DEBUG,
"No APs found - clear BSSID ignore list and try again");
+ wnm_btm_reset(wpa_s);
wpa_bssid_ignore_clear(wpa_s);
wpa_s->bssid_ignore_cleared = true;
} else if (selected == NULL)
@@ -2409,7 +2408,7 @@
scan_res = wpa_supplicant_get_scan_results(wpa_s,
data ? &data->scan_info :
- NULL, 1);
+ NULL, 1, NULL);
if (scan_res == NULL) {
if (wpa_s->conf->ap_scan == 2 || ap ||
wpa_s->scan_res_handler == scan_only_handler)
@@ -2498,7 +2497,7 @@
return 0;
}
- if (wnm_scan_process(wpa_s, 1) > 0)
+ if (wnm_scan_process(wpa_s, false) > 0)
goto scan_work_done;
if (sme_proc_obss_scan(wpa_s) > 0)
@@ -2941,8 +2940,6 @@
}
-#ifdef CONFIG_INTERWORKING
-
static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map,
size_t len)
{
@@ -2975,8 +2972,6 @@
}
}
-#endif /* CONFIG_INTERWORKING */
-
static void wpa_supplicant_set_4addr_mode(struct wpa_supplicant *wpa_s)
{
@@ -3002,25 +2997,24 @@
const u8 *ies, size_t ies_len)
{
struct ieee802_11_elems elems;
- const u8 *map_sub_elem, *pos;
- size_t len;
+ struct multi_ap_params multi_ap;
+ u16 status;
wpa_s->multi_ap_ie = 0;
if (!ies ||
ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed ||
- !elems.multi_ap || elems.multi_ap_len < 7)
+ !elems.multi_ap)
return;
- pos = elems.multi_ap + 4;
- len = elems.multi_ap_len - 4;
-
- map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
- if (!map_sub_elem || map_sub_elem[1] < 1)
+ status = check_multi_ap_ie(elems.multi_ap + 4, elems.multi_ap_len - 4,
+ &multi_ap);
+ if (status != WLAN_STATUS_SUCCESS)
return;
- wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS);
- wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] &
+ wpa_s->multi_ap_backhaul = !!(multi_ap.capability &
+ MULTI_AP_BACKHAUL_BSS);
+ wpa_s->multi_ap_fronthaul = !!(multi_ap.capability &
MULTI_AP_FRONTHAUL_BSS);
wpa_s->multi_ap_ie = 1;
}
@@ -3359,10 +3353,8 @@
wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_WNM */
-#ifdef CONFIG_INTERWORKING
interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
-#endif /* CONFIG_INTERWORKING */
if (wpa_s->hw_capab == CAPAB_VHT &&
get_ie(data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
@@ -3718,12 +3710,21 @@
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
- if (wpa_s->assoc_freq && data->assoc_info.freq &&
- wpa_s->assoc_freq != data->assoc_info.freq) {
- wpa_printf(MSG_DEBUG, "Operating frequency changed from "
- "%u to %u MHz",
- wpa_s->assoc_freq, data->assoc_info.freq);
- wpa_supplicant_update_scan_results(wpa_s);
+ if (wpa_s->assoc_freq && data->assoc_info.freq) {
+ struct wpa_bss *bss;
+ unsigned int freq = 0;
+
+ if (bssid_known) {
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss)
+ freq = bss->freq;
+ }
+ if (freq != data->assoc_info.freq) {
+ wpa_printf(MSG_DEBUG,
+ "Operating frequency changed from %u to %u MHz",
+ wpa_s->assoc_freq, data->assoc_info.freq);
+ wpa_supplicant_update_scan_results(wpa_s, bssid);
+ }
}
wpa_s->assoc_freq = data->assoc_info.freq;
@@ -4077,10 +4078,7 @@
if (!mlo.valid_links)
return 0;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(mlo.valid_links & BIT(i)))
- continue;
-
+ for_each_link(mlo.valid_links, i) {
if (!ether_addr_equal(wpa_s->links[i].addr,
mlo.links[i].addr) ||
!ether_addr_equal(wpa_s->links[i].bssid,
@@ -4098,10 +4096,7 @@
wpa_s->valid_links = mlo.valid_links;
wpa_s->mlo_assoc_link_id = mlo.assoc_link_id;
os_memcpy(wpa_s->ap_mld_addr, mlo.ap_mld_addr, ETH_ALEN);
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
os_memcpy(wpa_s->links[i].addr, mlo.links[i].addr, ETH_ALEN);
os_memcpy(wpa_s->links[i].bssid, mlo.links[i].bssid, ETH_ALEN);
wpa_s->links[i].freq = mlo.links[i].freq;
@@ -4134,15 +4129,13 @@
wpa_mlo.valid_links = drv_mlo.valid_links;
wpa_mlo.req_links = drv_mlo.req_links;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ for_each_link(drv_mlo.req_links, i) {
struct wpa_bss *bss;
- if (!(drv_mlo.req_links & BIT(i)))
- continue;
-
bss = wpa_supplicant_get_new_bss(wpa_s, drv_mlo.links[i].bssid);
if (!bss) {
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(
+ wpa_s, drv_mlo.links[i].bssid);
bss = wpa_supplicant_get_new_bss(
wpa_s, drv_mlo.links[i].bssid);
}
@@ -6021,13 +6014,10 @@
pos += res;
if (!info->default_map) {
- for (i = 0; i < MAX_NUM_MLD_LINKS && end > pos; i++) {
+ for_each_link(info->valid_links, i) {
char uplink_map_str[9];
char downlink_map_str[9];
- if (!(info->valid_links & BIT(i)))
- continue;
-
bitmap_to_str(info->t2lmap[i].uplink, uplink_map_str);
bitmap_to_str(info->t2lmap[i].downlink,
downlink_map_str);
@@ -6307,6 +6297,13 @@
" type=%d stype=%d",
MAC2STR(data->tx_status.dst),
data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_WNM
+ if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+ data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
+ wnm_btm_resp_tx_status(wpa_s, data->tx_status.data,
+ data->tx_status.data_len) == 0)
+ break;
+#endif /* CONFIG_WNM */
#ifdef CONFIG_PASN
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 498cc98..5676f38 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -2820,7 +2820,7 @@
struct wpa_bss *bss;
int res;
- bss = wpa_bss_get_bssid(wpa_s, dst);
+ bss = wpa_bss_get_bssid_latest(wpa_s, dst);
if (!bss && !freq) {
wpa_printf(MSG_WARNING,
"ANQP: Cannot send query without BSS freq info");
@@ -3175,7 +3175,7 @@
}
}
if (bss == NULL)
- bss = wpa_bss_get_bssid(wpa_s, dst);
+ bss = wpa_bss_get_bssid_latest(wpa_s, dst);
pos = wpabuf_head(resp);
end = pos + wpabuf_len(resp);
@@ -3206,12 +3206,12 @@
}
out_parse_done:
+ if (bss)
+ wpas_notify_bss_anqp_changed(wpa_s, bss->id);
#ifdef CONFIG_HS20
hs20_notify_parse_done(wpa_s);
#endif /* CONFIG_HS20 */
out:
- wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
- MAC2STR(dst), anqp_result);
wpas_notify_anqp_query_done(wpa_s, dst, anqp_result, bss ? bss->anqp : NULL);
}
@@ -3290,7 +3290,7 @@
u8 query_resp_len_limit = 0;
freq = wpa_s->assoc_freq;
- bss = wpa_bss_get_bssid(wpa_s, dst);
+ bss = wpa_bss_get_bssid_latest(wpa_s, dst);
if (bss)
freq = bss->freq;
if (freq <= 0)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 486fc6a..85c1ea8 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -231,7 +231,7 @@
hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf),
hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf),
ifmsh->conf->vht_capab,
- he_capab, NULL)) {
+ he_capab, NULL, 0)) {
wpa_printf(MSG_ERROR, "Error updating mesh frequency params");
wpa_supplicant_mesh_deinit(wpa_s, true);
return -1;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 6f162f2..c930651 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -627,6 +627,15 @@
}
+void wpas_notify_bss_anqp_changed(struct wpa_supplicant *wpa_s, unsigned int id)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_ANQP, id);
+}
+
+
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
{
if (wpa_s->p2p_mgmt)
@@ -935,7 +944,8 @@
const u8 *p2p_dev_addr, const u8 *ip)
{
if (authorized)
- wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr, ip);
+ wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr,
+ ip);
else
wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr, p2p_dev_addr);
}
@@ -1057,11 +1067,14 @@
const char *result,
const struct wpa_bss_anqp *anqp)
{
+ wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
+ MAC2STR(bssid), result);
#ifdef CONFIG_INTERWORKING
if (!wpa_s || !bssid || !anqp)
return;
wpas_aidl_notify_anqp_query_done(wpa_s, bssid, result, anqp);
+ wpas_dbus_signal_anqp_query_done(wpa_s, bssid, result);
#endif /* CONFIG_INTERWORKING */
}
@@ -1359,6 +1372,7 @@
wpas_dbus_signal_interworking_select_done(wpa_s);
}
+
#endif /* CONFIG_INTERWORKING */
void wpas_notify_eap_method_selected(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index d4656ad..a584884 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -89,6 +89,8 @@
void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
unsigned int id);
void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id);
+void wpas_notify_bss_anqp_changed(struct wpa_supplicant *wpa_s,
+ unsigned int id);
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index b4ad3ca..ff11d20 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -22,13 +22,12 @@
unsigned int *flags)
{
int i;
- bool is_6ghz = op_class >= 131 && op_class <= 136;
+ bool is_6ghz = is_6ghz_op_class(op_class);
for (i = 0; i < mode->num_channels; i++) {
bool chan_is_6ghz;
- chan_is_6ghz = mode->channels[i].freq >= 5935 &&
- mode->channels[i].freq <= 7115;
+ chan_is_6ghz = is_6ghz_freq(mode->channels[i].freq);
if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
@@ -187,6 +186,69 @@
}
+static int get_center_320mhz(struct hostapd_hw_modes *mode, u8 channel,
+ const u8 *center_channels, size_t num_chan)
+{
+ unsigned int i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A || !mode->is_6ghz)
+ return 0;
+
+ for (i = 0; i < num_chan; i++) {
+ /*
+ * In 320 MHz, the bandwidth "spans" 60 channels (e.g., 65-125),
+ * so the center channel is 30 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 30 &&
+ channel <= center_channels[i] + 30)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_320mhz(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+ bool no_ir = false;
+ const u8 *center_channels;
+ size_t num_chan;
+ const u8 center_channels_6ghz[] = { 31, 63, 95, 127, 159, 191 };
+
+ center_channels = center_channels_6ghz;
+ num_chan = ARRAY_SIZE(center_channels_6ghz);
+
+ center_chan = get_center_320mhz(mode, channel, center_channels,
+ num_chan);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* Check all the channels are available */
+ for (i = 0; i < 16; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 30 + i * 4;
+
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if (!(flags & HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL))
+ return NOT_ALLOWED;
+
+ if (flags & HOSTAPD_CHAN_NO_IR)
+ no_ir = true;
+ }
+
+ if (no_ir)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
u8 channel, u8 bw)
{
@@ -228,6 +290,13 @@
* result and use only the 80 MHz specific version.
*/
res2 = res = verify_80mhz(mode, op_class, channel);
+ } else if (bw == BW320) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 320 MHz specific version.
+ */
+ res2= res = verify_320mhz(mode, op_class, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -251,6 +320,7 @@
int z;
int freq2 = 0;
int freq5 = 0;
+ bool freq6 = false;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode,
is_6ghz_op_class(op_class->op_class));
@@ -265,7 +335,9 @@
if (f == 0)
break; /* end of list */
- if (f > 4000 && f < 6000)
+ if (is_6ghz_freq(f))
+ freq6 = true;
+ else if (f > 4000 && f < 6000)
freq5 = 1;
else if (f > 2400 && f < 2500)
freq2 = 1;
@@ -274,8 +346,11 @@
/* No frequencies specified, can use anything hardware supports.
*/
freq2 = freq5 = 1;
+ freq6 = true;
}
+ if (is_6ghz_op_class(op_class->op_class) && !freq6)
+ return 0;
if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5)
return 0;
if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2)
@@ -453,6 +528,7 @@
u8 op, current, chan;
u8 *ie_len;
size_t res;
+ bool op128 = false, op130 = false, op133 = false, op135 = false;
/*
* Determine the current operating class correct mode based on
@@ -480,8 +556,50 @@
wpabuf_put_u8(buf, current);
for (op = 0; global_op_class[op].op_class; op++) {
- if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op]))
- wpabuf_put_u8(buf, global_op_class[op].op_class);
+ bool supp;
+ u8 op_class = global_op_class[op].op_class;
+
+ supp = wpas_op_class_supported(wpa_s, ssid,
+ &global_op_class[op]);
+ if (!supp)
+ continue;
+ switch (op_class) {
+ case 128:
+ op128 = true;
+ break;
+ case 130:
+ op130 = true;
+ break;
+ case 133:
+ op133 = true;
+ break;
+ case 135:
+ op135 = true;
+ break;
+ }
+ if (is_80plus_op_class(op_class))
+ continue;
+
+ /* Add a 1-octet operating class to the Operating Class field */
+ wpabuf_put_u8(buf, global_op_class[op].op_class);
+ }
+
+ /* Add the 2-octet operating classes (i.e., 80+80 MHz cases), if any */
+ if ((op128 && op130) || (op133 && op135)) {
+ /* Operating Class Duple Sequence field */
+
+ /* Zero Delimiter */
+ wpabuf_put_u8(buf, 0);
+
+ /* Operating Class Duple List */
+ if (op128 && op130) {
+ wpabuf_put_u8(buf, 130);
+ wpabuf_put_u8(buf, 128);
+ }
+ if (op133 && op135) {
+ wpabuf_put_u8(buf, 135);
+ wpabuf_put_u8(buf, 133);
+ }
}
*ie_len = wpabuf_len(buf) - 2;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 3c121c8..9c20ee5 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1103,6 +1103,8 @@
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+ wpa_s->p2p_go_no_pri_sec_switch = 0;
+
return 0;
}
@@ -7003,7 +7005,8 @@
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, selected_freq, vht_center_freq2,
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, selected_freq,
+ vht_center_freq2,
ht40, vht, max_oper_chwidth, he, edmg,
NULL))
return -1;
@@ -7097,7 +7100,7 @@
* fetch time on the same radio so it reflects the actual time the last
* scan result event occurred.
*/
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, go_bssid);
dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
radio_list) {
if (ifs == wpa_s)
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 2e65cf0..1bb38f7 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -166,7 +166,7 @@
bss = wpa_bss_get_bssid(wpa_s, peer_addr);
if (!bss) {
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, peer_addr);
bss = wpa_bss_get_bssid(wpa_s, peer_addr);
if (!bss) {
wpa_printf(MSG_DEBUG, "PASN: BSS not found");
@@ -560,9 +560,10 @@
derive_kdk = wpa_s->conf->force_kdk_derivation;
#endif /* CONFIG_TESTING_OPTIONS */
if (derive_kdk)
- pasn->kdk_len = WPA_KDK_MAX_LEN;
+ pasn_enable_kdk_derivation(pasn);
else
- pasn->kdk_len = 0;
+ pasn_disable_kdk_derivation(pasn);
+
wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
@@ -582,9 +583,8 @@
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
- pasn->rsnxe_capab = capab;
- pasn->send_mgmt = wpas_pasn_send_mlme;
-
+ pasn_set_rsnxe_caps(pasn, capab);
+ pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
ssid = wpa_config_get_network(wpa_s->conf, awork->network_id);
#ifdef CONFIG_SAE
@@ -594,7 +594,7 @@
"PASN: No network profile found for SAE");
goto fail;
}
- pasn->pt = wpas_pasn_sae_derive_pt(ssid, awork->group);
+ pasn_set_pt(pasn, wpas_pasn_sae_derive_pt(ssid, awork->group));
if (!pasn->pt) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PT");
goto fail;
@@ -629,8 +629,7 @@
}
#endif /* CONFIG_FILS */
- pasn->cb_ctx = wpa_s;
- pasn->pmksa = wpa_sm_get_pmksa_cache(wpa_s->wpa);
+ pasn_set_initiator_pmksa(pasn, wpa_sm_get_pmksa_cache(wpa_s->wpa));
if (wpa_key_mgmt_ft(awork->akmp)) {
#ifdef CONFIG_IEEE80211R
@@ -753,7 +752,8 @@
wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
- wpas_pasn_auth_status(wpa_s, pasn->peer_addr, pasn->akmp, pasn->cipher,
+ wpas_pasn_auth_status(wpa_s, pasn->peer_addr, pasn_get_akmp(pasn),
+ pasn_get_cipher(pasn),
pasn->status, pasn->comeback,
pasn->comeback_after);
@@ -765,8 +765,8 @@
struct pasn_data *pasn,
struct wpa_pasn_params_data *params)
{
- int akmp = pasn->akmp;
- int cipher = pasn->cipher;
+ int akmp = pasn_get_akmp(pasn);
+ int cipher = pasn_get_cipher(pasn);
u16 group = pasn->group;
u8 own_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN];
@@ -806,20 +806,22 @@
if (!wpa_s->pasn_auth_work)
return -2;
- pasn->cb_ctx = wpa_s;
+ pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
if (ret == 0) {
ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->peer_addr,
- pasn->cipher, dot11RSNAConfigPMKLifetime,
- &pasn->ptk,
+ pasn_get_cipher(pasn),
+ dot11RSNAConfigPMKLifetime,
+ pasn_get_ptk(pasn),
wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL,
- wpa_s->pasn_params ? wpa_s : NULL, pasn->akmp);
+ wpa_s->pasn_params ? wpa_s : NULL,
+ pasn_get_akmp(pasn));
if (pasn->pmksa_entry)
wpa_sm_set_cur_pmksa(wpa_s->wpa, pasn->pmksa_entry);
}
- forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
+ forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
if (ret == -1) {
wpas_pasn_auth_stop(wpa_s);
@@ -909,7 +911,8 @@
}
wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr, pasn->peer_addr,
- pasn->cipher, pasn->akmp);
+ pasn_get_cipher(pasn),
+ pasn_get_akmp(pasn));
wpas_pasn_auth_stop(wpa_s);
wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 7ce854b..2ec4310 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -515,6 +515,8 @@
num_primary_channels = 4;
else if (op->bw == BW160)
num_primary_channels = 8;
+ else if (op->bw == BW320)
+ num_primary_channels = 16;
else
num_primary_channels = 1;
@@ -561,6 +563,7 @@
u8 channels_80mhz_6ghz[] = { 7, 23, 39, 55, 71, 87, 103, 119, 135, 151,
167, 183, 199, 215 };
u8 channels_160mhz_6ghz[] = { 15, 47, 79, 111, 143, 175, 207 };
+ u8 channels_320mhz_6ghz[] = { 31, 63, 95, 127, 159, 191 };
const u8 *channels = NULL;
size_t num_chan = 0;
bool is_6ghz = is_6ghz_op_class(op->op_class);
@@ -579,6 +582,9 @@
channels_160mhz_5ghz;
num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) :
ARRAY_SIZE(channels_160mhz_5ghz);
+ } else if (op->bw == BW320) {
+ channels = channels_320mhz_6ghz;
+ num_chan = ARRAY_SIZE(channels_320mhz_6ghz);
}
return wpas_add_channels(op, mode, channels, num_chan);
@@ -1520,10 +1526,7 @@
if (!wpa_s->valid_links)
return ether_addr_equal(wpa_s->current_bss->bssid, bssid);
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
if (ether_addr_equal(wpa_s->links[i].bssid, bssid))
return true;
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 6e6f05d..ccd694b 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -698,10 +698,7 @@
else
wpa_printf(MSG_DEBUG, "MLD: Probing links 0x%04x", links);
- for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
- if (!(links & BIT(link_id)))
- continue;
-
+ for_each_link(links, link_id) {
wpabuf_put_u8(extra_ie, EHT_ML_SUB_ELEM_PER_STA_PROFILE);
/* Subelement length includes only the control */
@@ -2606,8 +2603,8 @@
}
-void filter_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *res)
+static void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res)
{
size_t i, j;
@@ -3169,6 +3166,7 @@
* @wpa_s: Pointer to wpa_supplicant data
* @info: Information about what was scanned or %NULL if not available
* @new_scan: Whether a new scan was performed
+ * @bssid: Return BSS entries only for a single BSSID, %NULL for all
* Returns: Scan results, %NULL on failure
*
* This function request the current scan results from the driver and updates
@@ -3177,13 +3175,14 @@
*/
struct wpa_scan_results *
wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
- struct scan_info *info, int new_scan)
+ struct scan_info *info, int new_scan,
+ const u8 *bssid)
{
struct wpa_scan_results *scan_res;
size_t i;
int (*compar)(const void *, const void *) = wpa_scan_result_compar;
- scan_res = wpa_drv_get_scan_results2(wpa_s);
+ scan_res = wpa_drv_get_scan_results(wpa_s, bssid);
if (scan_res == NULL) {
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
return NULL;
@@ -3241,6 +3240,7 @@
/**
* wpa_supplicant_update_scan_results - Update scan results from the driver
* @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: Update BSS entries only for a single BSSID, %NULL for all
* Returns: 0 on success, -1 on failure
*
* This function updates the BSS table within wpa_supplicant based on the
@@ -3250,10 +3250,11 @@
* needed information to complete the connection (e.g., to perform validation
* steps in 4-way handshake).
*/
-int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
{
struct wpa_scan_results *scan_res;
- scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0, bssid);
if (scan_res == NULL)
return -1;
wpa_scan_results_free(scan_res);
@@ -3350,6 +3351,7 @@
params->duration = src->duration;
params->duration_mandatory = src->duration_mandatory;
params->oce_scan = src->oce_scan;
+ params->link_id = src->link_id;
if (src->sched_scan_plans_num > 0) {
params->sched_scan_plans =
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 8402e74..d4c06c1 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -54,8 +54,10 @@
bool default_ies, bool next);
struct wpa_scan_results *
wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
- struct scan_info *info, int new_scan);
-int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
+ struct scan_info *info, int new_scan,
+ const u8 *bssid);
+int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type);
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
@@ -86,8 +88,6 @@
int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
unsigned int type, u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
-void filter_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *res);
void scan_snr(struct wpa_scan_res *res);
void scan_est_throughput(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index b8f7c65..be0bc0d 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -182,7 +182,7 @@
if (!bss) {
wpa_printf(MSG_DEBUG,
"SAE: BSS not available, update scan result to get BSS");
- wpa_supplicant_update_scan_results(wpa_s);
+ wpa_supplicant_update_scan_results(wpa_s, bssid);
bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
}
if (bss) {
@@ -405,10 +405,7 @@
return bss;
if (!is_zero_ether_addr(wpa_s->conf->mld_connect_bssid_pref)) {
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
if (wpa_s->mlo_assoc_link_id == i)
continue;
@@ -439,10 +436,7 @@
return bss;
}
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
if (wpa_s->mlo_assoc_link_id == i)
continue;
@@ -523,21 +517,23 @@
static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
- int i;
+ u8 i;
wpa_s->valid_links = 0;
+ wpa_s->mlo_assoc_link_id = bss->mld_link_id;
- for (i = 0; i < bss->n_mld_links; i++) {
- u8 link_id = bss->mld_links[i].link_id;
+ for_each_link(bss->valid_links, i) {
const u8 *bssid = bss->mld_links[i].bssid;
- if (i == 0)
- wpa_s->mlo_assoc_link_id = link_id;
- wpa_s->valid_links |= BIT(link_id);
- os_memcpy(wpa_s->links[link_id].bssid, bssid, ETH_ALEN);
- wpa_s->links[link_id].freq = bss->mld_links[i].freq;
- wpa_s->links[link_id].bss = wpa_bss_get_bssid(wpa_s, bssid);
- wpa_s->links[link_id].disabled = bss->mld_links[i].disabled;
+ wpa_s->valid_links |= BIT(i);
+ os_memcpy(wpa_s->links[i].bssid, bssid, ETH_ALEN);
+ wpa_s->links[i].freq = bss->mld_links[i].freq;
+ wpa_s->links[i].disabled = bss->mld_links[i].disabled;
+
+ if (bss->mld_link_id == i)
+ wpa_s->links[i].bss = bss;
+ else
+ wpa_s->links[i].bss = wpa_bss_get_bssid(wpa_s, bssid);
}
}
@@ -578,7 +574,7 @@
if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) &&
!wpa_bss_parse_basic_ml_element(wpa_s, bss, wpa_s->ap_mld_addr,
NULL, ssid, NULL) &&
- bss->n_mld_links) {
+ bss->valid_links) {
wpa_printf(MSG_DEBUG, "MLD: In authentication");
wpas_sme_set_mlo_links(wpa_s, bss);
@@ -2416,12 +2412,16 @@
if (ssid && ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
+ struct multi_ap_params multi_ap = { 0 };
+
+ multi_ap.capability = MULTI_AP_BACKHAUL_STA;
+ multi_ap.profile = ssid->multi_ap_profile;
multi_ap_ie_len = add_multi_ap_ie(
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
sizeof(wpa_s->sme.assoc_req_ie) -
wpa_s->sme.assoc_req_ie_len,
- MULTI_AP_BACKHAUL_STA);
+ &multi_ap);
if (multi_ap_ie_len == 0) {
wpa_printf(MSG_ERROR,
"Multi-AP: Failed to build Multi-AP IE");
@@ -2601,10 +2601,7 @@
params.mld_params.mld_addr = wpa_s->ap_mld_addr;
params.mld_params.valid_links = wpa_s->valid_links;
params.mld_params.assoc_link_id = wpa_s->mlo_assoc_link_id;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
params.mld_params.mld_links[i].bssid =
wpa_s->links[i].bssid;
params.mld_params.mld_links[i].freq =
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 775e75b..ea79ae6 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -418,7 +418,7 @@
}
-void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
+void wnm_btm_reset(struct wpa_supplicant *wpa_s)
{
int i;
@@ -431,8 +431,17 @@
os_free(wpa_s->wnm_neighbor_report_elements);
wpa_s->wnm_neighbor_report_elements = NULL;
- wpabuf_free(wpa_s->coloc_intf_elems);
- wpa_s->coloc_intf_elems = NULL;
+ wpa_s->wnm_cand_valid_until.sec = 0;
+ wpa_s->wnm_cand_valid_until.usec = 0;
+
+ wpa_s->wnm_mode = 0;
+ wpa_s->wnm_dialog_token = 0;
+ wpa_s->wnm_reply = 0;
+
+#ifdef CONFIG_MBO
+ wpa_s->wnm_mbo_trans_reason_present = 0;
+ wpa_s->wnm_mbo_transition_reason = 0;
+#endif /* CONFIG_MBO */
}
@@ -781,22 +790,11 @@
}
}
- if (bss->ssid_len != target->ssid_len ||
- os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
- /*
- * TODO: Could consider allowing transition to another
- * ESS if PMF was enabled for the association.
- */
- wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
- " (pref %d) in different ESS",
- MAC2STR(nei->bssid),
- nei->preference_present ? nei->preference :
- -1);
- continue;
- }
-
- if (wpa_s->current_ssid &&
- !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
+ /*
+ * TODO: Could consider allowing transition to another ESS if
+ * PMF was enabled for the association.
+ */
+ if (!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
1, 0)) {
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
" (pref %d) does not match the current network profile",
@@ -806,14 +804,6 @@
continue;
}
- if (wpa_is_bss_tmp_disallowed(wpa_s, target)) {
- wpa_printf(MSG_DEBUG,
- "MBO: Candidate BSS " MACSTR
- " retry delay is not over yet",
- MAC2STR(nei->bssid));
- continue;
- }
-
if (target->level < bss->level && target->level < -80) {
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
" (pref %d) does not have sufficient signal level (%d)",
@@ -1045,8 +1035,8 @@
#define BTM_RESP_MIN_SIZE 5 + ETH_ALEN
-static void wnm_send_bss_transition_mgmt_resp(
- struct wpa_supplicant *wpa_s, u8 dialog_token,
+static int wnm_send_bss_transition_mgmt_resp(
+ struct wpa_supplicant *wpa_s,
enum bss_trans_mgmt_status_code status,
enum mbo_transition_reject_reason reason,
u8 delay, const u8 *target_bssid)
@@ -1054,21 +1044,24 @@
struct wpabuf *buf;
int res;
+ wpa_s->wnm_reply = 0;
+
wpa_printf(MSG_DEBUG,
"WNM: Send BSS Transition Management Response to " MACSTR
" dialog_token=%u status=%u reason=%u delay=%d",
- MAC2STR(wpa_s->bssid), dialog_token, status, reason, delay);
+ MAC2STR(wpa_s->bssid), wpa_s->wnm_dialog_token, status,
+ reason, delay);
if (!wpa_s->current_bss) {
wpa_printf(MSG_DEBUG,
"WNM: Current BSS not known - drop response");
- return;
+ return -1;
}
buf = wpabuf_alloc(BTM_RESP_MIN_SIZE);
if (!buf) {
wpa_printf(MSG_DEBUG,
"WNM: Failed to allocate memory for BTM response");
- return;
+ return -1;
}
wpa_s->bss_tm_status = status;
@@ -1076,7 +1069,7 @@
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
- wpabuf_put_u8(buf, dialog_token);
+ wpabuf_put_u8(buf, wpa_s->wnm_dialog_token);
wpabuf_put_u8(buf, status);
wpabuf_put_u8(buf, delay);
if (target_bssid) {
@@ -1090,7 +1083,7 @@
wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN);
}
- if (status == WNM_BSS_TM_ACCEPT && !wpa_s->wnm_link_removal)
+ if (status == WNM_BSS_TM_ACCEPT && target_bssid)
wnm_add_cand_list(wpa_s, &buf);
#ifdef CONFIG_MBO
@@ -1106,7 +1099,7 @@
wpabuf_free(buf);
wpa_printf(MSG_DEBUG,
"WNM: Failed to allocate memory for MBO IE");
- return;
+ return -1;
}
wpabuf_put_data(buf, mbo, ret);
@@ -1123,6 +1116,8 @@
}
wpabuf_free(buf);
+
+ return res;
}
@@ -1140,19 +1135,24 @@
/* Send the BSS Management Response - Accept */
if (wpa_s->wnm_reply) {
- wpa_s->wnm_reply = 0;
+ wpa_s->wnm_target_bss = bss;
wpa_printf(MSG_DEBUG,
"WNM: Sending successful BSS Transition Management Response");
- wnm_send_bss_transition_mgmt_resp(
- wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT,
- MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
- bss->bssid);
+
+ /* This function will be called again from the TX handler to
+ * start the actual reassociation after this response has been
+ * delivered to the current AP. */
+ if (wnm_send_bss_transition_mgmt_resp(
+ wpa_s, WNM_BSS_TM_ACCEPT,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+ bss->bssid) >= 0)
+ return;
}
if (bss == wpa_s->current_bss) {
wpa_printf(MSG_DEBUG,
"WNM: Already associated with the preferred candidate");
- wnm_deallocate_memory(wpa_s);
+ wnm_btm_reset(wpa_s);
return;
}
@@ -1168,11 +1168,10 @@
*/
if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
wpa_s->bss_trans_mgmt_in_progress = true;
- wnm_deallocate_memory(wpa_s);
}
-int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
+int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
{
struct wpa_bss *bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -1180,27 +1179,51 @@
enum mbo_transition_reject_reason reason =
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
- if (!wpa_s->wnm_neighbor_report_elements)
+ if (!wpa_s->wnm_dialog_token)
return 0;
wpa_dbg(wpa_s, MSG_DEBUG,
"WNM: Process scan results for BSS Transition Management");
- if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
+ if (!pre_scan_check &&
+ os_reltime_initialized(&wpa_s->wnm_cand_valid_until) &&
+ os_reltime_before(&wpa_s->wnm_cand_valid_until,
&wpa_s->scan_trigger_time)) {
wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
- wnm_deallocate_memory(wpa_s);
- return 0;
- }
-
- if (!wpa_s->current_bss ||
- !ether_addr_equal(wpa_s->wnm_cand_from_bss,
- wpa_s->current_bss->bssid)) {
- wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
- return 0;
+ goto send_bss_resp_fail;
}
/* Compare the Neighbor Report and scan results */
bss = compare_scan_neighbor_results(wpa_s, 0, &reason);
+
+ /*
+ * If this is a pre-scan check, returning 0 will trigger a scan and
+ * another call. In that case, reject "bad" candidates in the hope of
+ * finding a better candidate after scanning.
+ *
+ * Use a simple heuristic to check whether the selection is reasonable
+ * or a scan is a good idea. For that, we need to have found a
+ * candidate BSS (which might be the current one), it is up-to-date,
+ * and we don't want to immediately roam back again.
+ */
+ if (pre_scan_check) {
+ struct os_reltime age;
+
+ if (!bss)
+ return 0;
+
+ os_reltime_age(&bss->last_update, &age);
+ if (age.sec >= 10)
+ return 0;
+
+#ifndef CONFIG_NO_ROAMING
+ if (wpa_s->current_bss && bss != wpa_s->current_bss &&
+ wpa_supplicant_need_to_roam_within_ess(wpa_s,
+ wpa_s->current_bss,
+ bss))
+ return 0;
+#endif /* CONFIG_NO_ROAMING */
+ }
+
if (!bss) {
wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
@@ -1212,18 +1235,13 @@
return 1;
send_bss_resp_fail:
- if (!reply_on_fail)
- return 0;
-
/* Send reject response for all the failures */
- if (wpa_s->wnm_reply) {
- wpa_s->wnm_reply = 0;
- wnm_send_bss_transition_mgmt_resp(wpa_s,
- wpa_s->wnm_dialog_token,
- status, reason, 0, NULL);
- }
- wnm_deallocate_memory(wpa_s);
+ if (wpa_s->wnm_reply)
+ wnm_send_bss_transition_mgmt_resp(wpa_s, status, reason,
+ 0, NULL);
+
+ wnm_btm_reset(wpa_s);
return 0;
}
@@ -1330,6 +1348,10 @@
struct neighbor_report *nei;
nei = &wpa_s->wnm_neighbor_report_elements[i];
+
+ if (nei->preference_present && nei->preference == 0)
+ continue;
+
if (nei->freq <= 0) {
wpa_printf(MSG_DEBUG,
"WNM: Unknown neighbor operating frequency for "
@@ -1354,79 +1376,6 @@
}
-static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
-{
- struct wpa_scan_results *scan_res;
- struct wpa_bss *bss;
- struct wpa_ssid *ssid = wpa_s->current_ssid;
- u8 i, found = 0;
- size_t j;
-
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WNM: Fetch current scan results from the driver for checking transition candidates");
- scan_res = wpa_drv_get_scan_results2(wpa_s);
- if (!scan_res) {
- wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results");
- return 0;
- }
-
- if (scan_res->fetch_time.sec == 0)
- os_get_reltime(&scan_res->fetch_time);
-
- filter_scan_res(wpa_s, scan_res);
-
- for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
- struct neighbor_report *nei;
-
- nei = &wpa_s->wnm_neighbor_report_elements[i];
- if (nei->preference_present && nei->preference == 0)
- continue;
-
- for (j = 0; j < scan_res->num; j++) {
- struct wpa_scan_res *res;
- const u8 *ssid_ie;
-
- res = scan_res->res[j];
- if (!ether_addr_equal(nei->bssid, res->bssid) ||
- res->age > WNM_SCAN_RESULT_AGE * 1000)
- continue;
- bss = wpa_s->current_bss;
- ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
- if (bss && ssid_ie && ssid_ie[1] &&
- (bss->ssid_len != ssid_ie[1] ||
- os_memcmp(bss->ssid, ssid_ie + 2,
- bss->ssid_len) != 0))
- continue; /* Skip entries for other ESSs */
-
- /* Potential candidate found */
- found = 1;
- scan_snr(res);
- scan_est_throughput(wpa_s, res);
- wpa_bss_update_scan_res(wpa_s, res,
- &scan_res->fetch_time);
- }
- }
-
- wpa_scan_results_free(scan_res);
- if (!found) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WNM: No transition candidate matches existing scan results");
- return 0;
- }
-
- bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL);
- if (!bss) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WNM: Comparison of scan results against transition candidates did not find matches");
- return 0;
- }
-
- /* Associate to the network */
- wnm_bss_tm_connect(wpa_s, bss, ssid, 0);
- return 1;
-}
-
-
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
@@ -1445,8 +1394,6 @@
return;
#ifdef CONFIG_MBO
- wpa_s->wnm_mbo_trans_reason_present = 0;
- wpa_s->wnm_mbo_transition_reason = 0;
wpa_s->wnm_mbo_cell_pref_present = 0;
wpa_s->wnm_mbo_cell_preference = 0;
wpa_s->wnm_mbo_assoc_retry_delay_present = 0;
@@ -1458,6 +1405,8 @@
else
beacon_int = 100; /* best guess */
+ wnm_btm_reset(wpa_s);
+
wpa_s->wnm_dialog_token = pos[0];
wpa_s->wnm_mode = pos[1];
wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
@@ -1477,8 +1426,7 @@
"WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
wpa_s->reject_btm_req_reason);
wnm_send_bss_transition_mgmt_resp(
- wpa_s, wpa_s->wnm_dialog_token,
- wpa_s->reject_btm_req_reason,
+ wpa_s, wpa_s->reject_btm_req_reason,
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
return;
}
@@ -1541,15 +1489,34 @@
* set to 1, and the BSS Termination Included field is set to 1, only
* one of the links is removed and the other links remain associated.
* Ignore the Disassociation Imminent field in such a case.
+ *
+ * TODO: We should check if the AP has more than one link.
+ * TODO: We should pass the RX link and use that
*/
- if (disassoc_imminent &&
- (wpa_s->valid_links & (wpa_s->valid_links - 1)) != 0 &&
+ if (disassoc_imminent && wpa_s->valid_links &&
(wpa_s->wnm_mode & WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT) &&
(wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED)) {
- wpa_printf(MSG_INFO,
- "WNM: BTM request for a single MLO link - ignore disassociation imminent since other links remain associated");
- disassoc_imminent = false;
+ /* If we still have a link, then just accept the request */
+ if (wpa_s->valid_links & (wpa_s->valid_links - 1)) {
+ wpa_printf(MSG_INFO,
+ "WNM: BTM request for a single MLO link - ignore disassociation imminent since other links remain associated");
+ disassoc_imminent = false;
+
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, WNM_BSS_TM_ACCEPT, 0, 0, NULL);
+
+ return;
+ }
+
+ /* The last link is being removed (which must be the assoc link)
+ */
wpa_s->wnm_link_removal = true;
+ os_memcpy(wpa_s->wnm_dissoc_addr,
+ wpa_s->links[wpa_s->mlo_assoc_link_id].bssid,
+ ETH_ALEN);
+ } else {
+ os_memcpy(wpa_s->wnm_dissoc_addr, wpa_s->valid_links ?
+ wpa_s->ap_mld_addr : wpa_s->bssid, ETH_ALEN);
}
if (disassoc_imminent) {
@@ -1566,7 +1533,6 @@
unsigned int valid_ms;
wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
- wnm_deallocate_memory(wpa_s);
wpa_s->wnm_neighbor_report_elements = os_calloc(
WNM_MAX_NEIGHBOR_REPORT,
sizeof(struct neighbor_report));
@@ -1614,8 +1580,7 @@
wpa_printf(MSG_DEBUG,
"WNM: Candidate list included bit is set, but no candidates found");
wnm_send_bss_transition_mgmt_resp(
- wpa_s, wpa_s->wnm_dialog_token,
- WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+ wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
NULL);
return;
@@ -1625,8 +1590,7 @@
wpa_printf(MSG_DEBUG,
"WNM: Configuration prevents roaming (BSSID set)");
wnm_send_bss_transition_mgmt_resp(
- wpa_s, wpa_s->wnm_dialog_token,
- WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+ wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
NULL);
return;
@@ -1643,35 +1607,21 @@
wpa_s->wnm_cand_valid_until.sec +=
wpa_s->wnm_cand_valid_until.usec / 1000000;
wpa_s->wnm_cand_valid_until.usec %= 1000000;
- os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
/*
- * Fetch the latest scan results from the kernel and check for
- * candidates based on those results first. This can help in
- * finding more up-to-date information should the driver has
- * done some internal scanning operations after the last scan
- * result update in wpa_supplicant.
- */
- if (wnm_fetch_scan_results(wpa_s) > 0)
+ * Try fetching the latest scan results from the kernel.
+ * This can help in finding more up-to-date information should
+ * the driver have done some internal scanning operations after
+ * the last scan result update in wpa_supplicant.
+ *
+ * It is not a new scan, this does not update the last_scan
+ * timestamp nor will it expire old BSSs.
+ */
+ wpa_supplicant_update_scan_results(wpa_s, NULL);
+ if (wnm_scan_process(wpa_s, true) > 0)
return;
-
- /*
- * Try to use previously received scan results, if they are
- * recent enough to use for a connection.
- */
- if (wpa_s->last_scan_res_used > 0) {
- struct os_reltime now;
-
- os_get_reltime(&now);
- if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
- wpa_printf(MSG_DEBUG,
- "WNM: Try to use recent scan results");
- if (wnm_scan_process(wpa_s, 0) > 0)
- return;
- wpa_printf(MSG_DEBUG,
- "WNM: No match in previous scan results - try a new scan");
- }
- }
+ wpa_printf(MSG_DEBUG,
+ "WNM: No valid match in previous scan results - try a new scan");
wnm_set_scan_freqs(wpa_s);
if (wpa_s->wnm_num_neighbor_report == 1) {
@@ -1694,12 +1644,45 @@
status = WNM_BSS_TM_REJECT_UNSPECIFIED;
}
wnm_send_bss_transition_mgmt_resp(
- wpa_s, wpa_s->wnm_dialog_token, status,
+ wpa_s, status,
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
}
}
+int wnm_btm_resp_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+ size_t data_len)
+{
+ const struct ieee80211_mgmt *frame =
+ (const struct ieee80211_mgmt *) data;
+
+ if (data_len <
+ IEEE80211_HDRLEN + sizeof(frame->u.action.u.bss_tm_resp) ||
+ frame->u.action.category != WLAN_ACTION_WNM ||
+ frame->u.action.u.bss_tm_resp.action != WNM_BSS_TRANS_MGMT_RESP ||
+ frame->u.action.u.bss_tm_resp.status_code != WNM_BSS_TM_ACCEPT)
+ return -1;
+
+ /*
+ * If disassoc imminent bit was set in the request, the response may
+ * indicate accept even if no candidate was found, so bail out here.
+ */
+ if (!wpa_s->wnm_target_bss) {
+ wpa_printf(MSG_DEBUG, "WNM: Target BSS is not set");
+ return 0;
+ }
+
+ if (!wpa_s->current_ssid)
+ return 0;
+
+ wnm_bss_tm_connect(wpa_s, wpa_s->wnm_target_bss, wpa_s->current_ssid,
+ 0);
+
+ wpa_s->wnm_target_bss = NULL;
+ return 0;
+}
+
+
#define BTM_QUERY_MIN_SIZE 4
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
@@ -2052,14 +2035,14 @@
void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
struct wpabuf *elems)
{
- wpabuf_free(wpa_s->coloc_intf_elems);
if (elems && wpabuf_len(elems) == 0) {
wpabuf_free(elems);
elems = NULL;
}
- wpa_s->coloc_intf_elems = elems;
- if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems &&
+ /* NOTE: The elements are not stored as they are only send out once */
+
+ if (wpa_s->conf->coloc_intf_reporting && elems &&
wpa_s->coloc_intf_dialog_token &&
(wpa_s->coloc_intf_auto_report == 1 ||
wpa_s->coloc_intf_auto_report == 3)) {
@@ -2068,8 +2051,10 @@
*/
wnm_send_coloc_intf_report(wpa_s,
wpa_s->coloc_intf_dialog_token,
- wpa_s->coloc_intf_elems);
+ elems);
}
+
+ wpabuf_free(elems);
}
@@ -2082,8 +2067,6 @@
bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- unsigned int i;
-
if (!(wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))
return false;
@@ -2091,26 +2074,14 @@
* In case disassociation imminent is set, do no try to use a BSS to
* which we are connected.
*/
-
- if (wpa_s->current_bss &&
- ether_addr_equal(wpa_s->current_bss->bssid, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WNM: Disassociation imminent: current BSS");
- return true;
- }
-
- if (!wpa_s->valid_links)
- return false;
-
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
- if (ether_addr_equal(wpa_s->links[i].bssid, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WNM: MLD: Disassociation imminent: current link");
+ if (wpa_s->wnm_link_removal ||
+ !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) ||
+ is_zero_ether_addr(bss->mld_addr)) {
+ if (ether_addr_equal(bss->bssid, wpa_s->wnm_dissoc_addr))
return true;
- }
+ } else {
+ if (ether_addr_equal(bss->mld_addr, wpa_s->wnm_dissoc_addr))
+ return true;
}
return false;
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 2a473db..235a838 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -65,19 +65,28 @@
const char *btm_candidates,
int cand_list);
-void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
const struct wpabuf *elems);
void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
struct wpabuf *elems);
-bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+int wnm_btm_resp_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+ size_t data_len);
#ifdef CONFIG_WNM
-int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check);
void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s);
+bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+
+void wnm_btm_reset(struct wpa_supplicant *wpa_s);
+
+static inline bool wnm_active_bss_trans_mgmt(struct wpa_supplicant *wpa_s)
+{
+ return !!wpa_s->wnm_dialog_token;
+}
+
#else /* CONFIG_WNM */
static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
@@ -90,6 +99,21 @@
{
}
+static inline bool
+wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ return false;
+}
+
+static inline void wnm_btm_reset(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline bool wnm_active_bss_trans_mgmt(struct wpa_supplicant *wpa_s)
+{
+ return false;
+}
+
#endif /* CONFIG_WNM */
#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index b1334e2..60f8562 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -5129,7 +5129,7 @@
eloop_register_signal_terminate(wpa_cli_terminate, NULL);
- if (ctrl_ifname == NULL)
+ if (!ctrl_ifname && !global)
ctrl_ifname = wpa_cli_get_default_ifname();
if (reconnect && action_file && ctrl_ifname) {
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 31a9af6..88f3f2a 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -187,7 +187,10 @@
int val;
size_t i;
- res = iface->driver->get_scan_results2(iface->drv_priv);
+ if (iface->driver->get_scan_results)
+ res = iface->driver->get_scan_results(iface->drv_priv, NULL);
+ else
+ res = iface->driver->get_scan_results2(iface->drv_priv);
if (res == NULL)
goto fail;
@@ -231,7 +234,7 @@
if (iface->drv_priv == NULL)
return;
- if (iface->driver->get_scan_results2)
+ if (iface->driver->get_scan_results || iface->driver->get_scan_results2)
wpa_priv_get_scan_results2(iface, from, fromlen);
else
sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index a851024..3fde0a8 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -678,9 +678,7 @@
wpa_s->disallow_aps_ssid = NULL;
wnm_bss_keep_alive_deinit(wpa_s);
-#ifdef CONFIG_WNM
- wnm_deallocate_memory(wpa_s);
-#endif /* CONFIG_WNM */
+ wnm_btm_reset(wpa_s);
ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL;
@@ -894,7 +892,7 @@
struct wpa_scan_results *scan_res;
wpa_s->bgscan_ssid = wpa_s->current_ssid;
scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
- 0);
+ 0, NULL);
if (scan_res) {
bgscan_notify_scan(wpa_s, scan_res);
wpa_scan_results_free(scan_res);
@@ -1081,6 +1079,10 @@
if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
wpa_supplicant_start_autoscan(wpa_s);
+ if (state == WPA_COMPLETED || state == WPA_INTERFACE_DISABLED ||
+ state == WPA_INACTIVE)
+ wnm_btm_reset(wpa_s);
+
#ifndef CONFIG_NO_WMM_AC
if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
wmm_ac_notify_disassoc(wpa_s);
@@ -2522,6 +2524,7 @@
#endif /* CONFIG_NO_WMM_AC */
#ifdef CONFIG_WNM
wpa_s->wnm_mode = 0;
+ wpa_s->wnm_target_bss = NULL;
#endif /* CONFIG_WNM */
wpa_s->reassoc_same_bss = 0;
wpa_s->reassoc_same_ess = 0;
@@ -2919,7 +2922,8 @@
if (obss_scan) {
struct wpa_scan_results *scan_res;
- scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0,
+ NULL);
if (scan_res == NULL) {
/* Back to HT20 */
freq->sec_channel_offset = 0;
@@ -3083,7 +3087,7 @@
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
&mode->he_capab[ieee80211_mode],
- &mode->eht_capab[ieee80211_mode]) != 0)
+ &mode->eht_capab[ieee80211_mode], 0) != 0)
return false;
*freq = vht_freq;
@@ -3831,10 +3835,14 @@
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
+ struct multi_ap_params multi_ap = { 0 };
+
+ multi_ap.capability = MULTI_AP_BACKHAUL_STA;
+ multi_ap.profile = ssid->multi_ap_profile;
multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
max_wpa_ie_len - wpa_ie_len,
- MULTI_AP_BACKHAUL_STA);
+ &multi_ap);
if (multi_ap_ie_len == 0) {
wpa_printf(MSG_ERROR,
"Multi-AP: Failed to build Multi-AP IE");
@@ -9173,8 +9181,7 @@
if (modes[i].mode != mode ||
!modes[i].num_channels || !modes[i].channels)
continue;
- if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) ||
- (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq)))
+ if (is_6ghz == modes[i].is_6ghz)
return &modes[i];
}
@@ -9413,17 +9420,21 @@
struct wpa_scan_results *
-wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
+wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_scan_results *scan_res;
#ifdef CONFIG_TESTING_OPTIONS
size_t idx;
#endif /* CONFIG_TESTING_OPTIONS */
- if (!wpa_s->driver->get_scan_results2)
+ if (wpa_s->driver->get_scan_results)
+ scan_res = wpa_s->driver->get_scan_results(wpa_s->drv_priv,
+ bssid);
+ else if (wpa_s->driver->get_scan_results2)
+ scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+ else
return NULL;
- scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
#ifdef CONFIG_TESTING_OPTIONS
for (idx = 0; scan_res && idx < scan_res->num; idx++) {
@@ -9461,10 +9472,7 @@
if (!wpa_s->valid_links)
return false;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
- if (!(wpa_s->valid_links & BIT(i)))
- continue;
-
+ for_each_link(wpa_s->valid_links, i) {
if (ether_addr_equal(wpa_s->links[i].bssid, addr))
return true;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index d689441..89c5d03 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1717,6 +1717,12 @@
# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be
# added to a bridge to allow forwarding frames over this backhaul link.
+# Multi-AP Profile
+# Indicate the supported Multi-AP profile
+# 1 = Supports Multi-AP profile 1 as defined in Wi-Fi EasyMesh specification
+# 2 = Supports Multi-AP profile 2 as defined in Wi-Fi EasyMesh specification
+#multi_ap_profile=2
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3a5f61c..0fea5cc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1327,14 +1327,14 @@
u8 wnm_num_neighbor_report;
u8 wnm_mode;
bool wnm_link_removal;
+ u8 wnm_dissoc_addr[ETH_ALEN];
u16 wnm_dissoc_timer;
u8 wnm_bss_termination_duration[12];
struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until;
- u8 wnm_cand_from_bss[ETH_ALEN];
+ struct wpa_bss *wnm_target_bss;
enum bss_trans_mgmt_status_code bss_tm_status;
bool bss_trans_mgmt_in_progress;
- struct wpabuf *coloc_intf_elems;
u8 coloc_intf_dialog_token;
u8 coloc_intf_auto_report;
u8 coloc_intf_timeout;
@@ -1500,6 +1500,9 @@
int dpp_netrole;
int dpp_auth_ok_on_ack;
int dpp_in_response_listen;
+ bool dpp_tx_auth_resp_on_roc_stop;
+ bool dpp_tx_chan_change;
+ bool dpp_listen_on_tx_expire;
int dpp_gas_client;
int dpp_gas_server;
int dpp_gas_dialog_token;
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 111680c..2fea640 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -465,7 +465,7 @@
/* No WPA/RSN IE found in the cached scan results. Try to get updated
* scan results from the driver. */
- if (wpa_supplicant_update_scan_results(wpa_s) < 0)
+ if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
return -1;
return wpa_get_beacon_ie(wpa_s);
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 81e11e7..f103237 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1208,14 +1208,19 @@
}
}
#endif /* CONFIG_P2P */
- os_snprintf(phase1, sizeof(phase1), "pbc=1%s",
- multi_ap_backhaul_sta ? " multi_ap=1" : "");
+ if (multi_ap_backhaul_sta)
+ os_snprintf(phase1, sizeof(phase1), "pbc=1 multi_ap=%d",
+ multi_ap_backhaul_sta);
+ else
+ os_snprintf(phase1, sizeof(phase1), "pbc=1");
if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0)
return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
- if (multi_ap_backhaul_sta)
+ if (multi_ap_backhaul_sta) {
ssid->multi_ap_backhaul_sta = 1;
+ ssid->multi_ap_profile = multi_ap_backhaul_sta;
+ }
wpa_s->supp_pbc_active = true;
wpa_s->wps_overlap = false;
wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);