Merge "Suppress existing clang-tidy warnings" am: c3b41ba025 am: 6ca59c4bfc am: 9e5c5fca0a
Original change: https://android-review.googlesource.com/c/platform/external/wpa_supplicant_8/+/2326253
Change-Id: I9210bebab44c651f0e8e007fe34a4b3d3a705da4
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/OWNERS b/OWNERS
index cd9dfa9..351212a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,2 @@
etancohen@google.com
-haishalom@google.com
arabawy@google.com
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index adb4c08..14a7464 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -272,6 +272,7 @@
OBJS += src/common/sae.c
ifdef CONFIG_SAE_PK
L_CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
OBJS += src/common/sae_pk.c
endif
NEED_ECC=y
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 5f06378..88a2e18 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -295,6 +295,7 @@
OBJS += ../src/common/sae.o
ifdef CONFIG_SAE_PK
CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
OBJS += ../src/common/sae_pk.o
endif
NEED_ECC=y
diff --git a/hostapd/aidl/aidl.cpp b/hostapd/aidl/aidl.cpp
index e02708c..c6088ed 100644
--- a/hostapd/aidl/aidl.cpp
+++ b/hostapd/aidl/aidl.cpp
@@ -34,7 +34,8 @@
int hostapd_aidl_init(struct hapd_interfaces *interfaces)
{
- wpa_printf(MSG_DEBUG, "Initializing aidl control");
+ wpa_printf(MSG_INFO, "Initializing aidl control");
+ wpa_printf(MSG_INFO, "Interface version: %d", Hostapd::version);
std::string instance; // declared here to allow use of goto
ABinderProcess_setupPolling(&aidl_fd);
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index 680d8d0..35bfbe7 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -671,27 +671,27 @@
iconf->vht_oper_chwidth, iconf->ieee80211n,
iconf->secondary_channel);
switch (iconf->vht_oper_chwidth) {
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
return ChannelBandwidth::BANDWIDTH_80;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
return ChannelBandwidth::BANDWIDTH_80P80;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
return ChannelBandwidth::BANDWIDTH_160;
break;
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (iconf->ieee80211n) {
return iconf->secondary_channel != 0 ?
ChannelBandwidth::BANDWIDTH_40 : ChannelBandwidth::BANDWIDTH_20;
}
return ChannelBandwidth::BANDWIDTH_20_NOHT;
- case CHANWIDTH_2160MHZ:
+ case CONF_OPER_CHWIDTH_2160MHZ:
return ChannelBandwidth::BANDWIDTH_2160;
- case CHANWIDTH_4320MHZ:
+ case CONF_OPER_CHWIDTH_4320MHZ:
return ChannelBandwidth::BANDWIDTH_4320;
- case CHANWIDTH_6480MHZ:
+ case CONF_OPER_CHWIDTH_6480MHZ:
return ChannelBandwidth::BANDWIDTH_6480;
- case CHANWIDTH_8640MHZ:
+ case CONF_OPER_CHWIDTH_8640MHZ:
return ChannelBandwidth::BANDWIDTH_8640;
default:
return ChannelBandwidth::BANDWIDTH_INVALID;
@@ -702,6 +702,9 @@
const std::vector<uint8_t>& client_address,
const uint16_t reason_code) {
struct sta_info *sta;
+ if (client_address.size() != ETH_ALEN) {
+ return false;
+ }
for (sta = hapd->sta_list; sta; sta = sta->next) {
int res;
res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
@@ -1028,7 +1031,7 @@
iface_hapd->setup_complete_cb_ctx = iface_hapd;
iface_hapd->sta_authorized_cb = onAsyncStaAuthorizedCb;
iface_hapd->sta_authorized_cb_ctx = iface_hapd;
- wpa_msg_register_cb(onAsyncWpaEventCb);
+ wpa_msg_register_aidl_cb(onAsyncWpaEventCb);
if (hostapd_enable_iface(iface_hapd->iface) < 0) {
wpa_printf(
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 2d5a510..24fd297 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -674,8 +674,12 @@
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "SAE-EXT-KEY") == 0)
+ val |= WPA_KEY_MGMT_SAE_EXT_KEY;
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
+ else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
#ifdef CONFIG_SUITEB
else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
@@ -2361,7 +2365,7 @@
}
os_memcpy(ssid->ssid, pos, ssid->ssid_len);
ssid->ssid_set = 1;
- ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
+ ssid->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
} else if (os_strcmp(buf, "ssid2") == 0) {
struct hostapd_ssid *ssid = &bss->ssid;
size_t slen;
@@ -2375,7 +2379,7 @@
os_memcpy(ssid->ssid, str, slen);
ssid->ssid_len = slen;
ssid->ssid_set = 1;
- ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
+ ssid->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
os_free(str);
} else if (os_strcmp(buf, "utf8_ssid") == 0) {
bss->ssid.utf8_ssid = atoi(pos) > 0;
@@ -4460,6 +4464,12 @@
} else if (os_strcmp(buf, "dpp_mud_url") == 0) {
os_free(bss->dpp_mud_url);
bss->dpp_mud_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "dpp_extra_conf_req_name") == 0) {
+ os_free(bss->dpp_extra_conf_req_name);
+ bss->dpp_extra_conf_req_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "dpp_extra_conf_req_value") == 0) {
+ os_free(bss->dpp_extra_conf_req_value);
+ bss->dpp_extra_conf_req_value = os_strdup(pos);
} else if (os_strcmp(buf, "dpp_connector") == 0) {
os_free(bss->dpp_connector);
bss->dpp_connector = os_strdup(pos);
@@ -4475,6 +4485,8 @@
} else if (os_strcmp(buf, "dpp_controller") == 0) {
if (hostapd_dpp_controller_parse(bss, pos))
return 1;
+ } else if (os_strcmp(buf, "dpp_relay_port") == 0) {
+ bss->dpp_relay_port = atoi(pos);
} else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) {
bss->dpp_configurator_connectivity = atoi(pos);
} else if (os_strcmp(buf, "dpp_pfs") == 0) {
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index ad994d4..7fb3fd3 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -861,6 +861,12 @@
return pos - buf;
pos += ret;
}
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, "FT-SAE-EXT-KEY ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
@@ -896,6 +902,12 @@
return pos - buf;
pos += ret;
}
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, "SAE-EXT-KEY ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
#endif /* CONFIG_SAE */
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
@@ -1686,7 +1698,7 @@
return -1;
}
- ieee802_1x_receive(hapd, src, buf, len);
+ ieee802_1x_receive(hapd, src, buf, len, FRAME_ENCRYPTION_UNKNOWN);
os_free(buf);
return 0;
@@ -2531,6 +2543,9 @@
case 160:
bandwidth = CHAN_WIDTH_160;
break;
+ case 320:
+ bandwidth = CHAN_WIDTH_320;
+ break;
default:
bandwidth = CHAN_WIDTH_20;
break;
@@ -3674,7 +3689,20 @@
reply_len = -1;
} else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
hostapd_dpp_chirp_stop(hapd);
+ } else if (os_strncmp(buf, "DPP_RELAY_ADD_CONTROLLER ", 25) == 0) {
+ if (hostapd_dpp_add_controller(hapd, buf + 25) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_RELAY_REMOVE_CONTROLLER ", 28) == 0) {
+ hostapd_dpp_remove_controller(hapd, buf + 28);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) {
+ if (hostapd_dpp_push_button(hapd, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_PUSH_BUTTON ", 16) == 0) {
+ if (hostapd_dpp_push_button(hapd, buf + 15) < 0)
+ reply_len = -1;
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
#ifdef RADIUS_SERVER
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
@@ -4183,6 +4211,19 @@
#ifdef CONFIG_DPP
dpp_global_clear(interfaces->dpp);
+#ifdef CONFIG_DPP3
+ {
+ int i;
+
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ struct dpp_pb_info *info;
+
+ info = &interfaces->dpp_pb[i];
+ info->rx_time.sec = 0;
+ info->rx_time.usec = 0;
+ }
+ }
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
}
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index f37d563..ea67aa1 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -871,7 +871,7 @@
# he_oper_chwidth is ignored, and the channel width is derived from the
# configured operating class or center frequency indexes (see
# IEEE P802.11ax/D6.1 Annex E, Table E-4).
-#he_oper_chwidth
+#he_oper_chwidth (see vht_oper_chwidth)
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@@ -1021,7 +1021,7 @@
# In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is
# derived from the configured operating class (IEEE P802.11be/D1.5,
# Annex E.1 - Country information and operating classes).
-#eht_oper_chwidth
+#eht_oper_chwidth (see vht_oper_chwidth)
#eht_oper_centr_freq_seg0_idx
##### IEEE 802.1X-2004 related configuration ##################################
@@ -2514,12 +2514,24 @@
# MUD URL for Enrollee's DPP Configuration Request (optional)
#dpp_mud_url=https://example.com/mud
+# JSON node name of additional data for Enrollee's DPP Configuration Request
+#dpp_extra_conf_req_name=org.example
+
+# JSON node data of additional data for Enrollee's DPP Configuration Request
+#dpp_extra_conf_req_value="abc":123
+
#dpp_connector
#dpp_netaccesskey
#dpp_netaccesskey_expiry
#dpp_csign
#dpp_controller
+# DPP Relay port number
+# TCP port to listen to for incoming connections from a Controller. This can be
+# used to allow Controller initiated exchanges in addition to the
+# Controller-as-responder cases covered by the dpp_controller parameter.
+#dpp_relay_port=12345
+
# Configurator Connectivity indication
# 0: no Configurator is currently connected (default)
# 1: advertise that a Configurator is available
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 60396f3..6376b78 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1478,7 +1478,7 @@
static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+ return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv);
}
@@ -1503,6 +1503,15 @@
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 1, argc, argv);
+}
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
@@ -1729,6 +1738,10 @@
{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
"= stop DPP chirp" },
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ { "dpp_push_button", hostapd_cli_cmd_dpp_push_button, NULL,
+ "= press DPP push button" },
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
"=Add/Delete/Show/Clear accept MAC ACL" },
diff --git a/hostapd/main.c b/hostapd/main.c
index eab57b6..822403f 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -468,7 +468,7 @@
show_version();
fprintf(stderr,
"\n"
- "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
+ "usage: hostapd [-hdBKtvq] [-P <PID file>] [-e <entropy file>] "
"\\\n"
" [-g <global ctrl_iface>] [-G <group>]\\\n"
" [-i <comma-separated list of interface names>]\\\n"
@@ -496,7 +496,8 @@
#endif /* CONFIG_DEBUG_SYSLOG */
" -S start all the interfaces synchronously\n"
" -t include timestamps in some debug messages\n"
- " -v show hostapd version\n");
+ " -v show hostapd version\n"
+ " -q show less debug messages (-qq for even less)\n");
exit(1);
}
@@ -687,7 +688,7 @@
#endif /* CONFIG_DPP */
for (;;) {
- c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
+ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q");
if (c < 0)
break;
switch (c) {
@@ -760,6 +761,9 @@
&if_names_size, optarg))
goto out;
break;
+ case 'q':
+ wpa_debug_level++;
+ break;
default:
usage();
break;
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 7b274da..01e7b75 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2018,6 +2018,7 @@
struct osu_data *osu = NULL, *last = NULL;
size_t osu_count = 0;
char *pos, *end;
+ int res;
f = fopen(fname, "r");
if (f == NULL) {
@@ -2037,15 +2038,20 @@
osu = last;
last = &osu[osu_count++];
memset(last, 0, sizeof(*last));
- snprintf(last->bssid, sizeof(last->bssid), "%s",
- buf + 13);
+ res = os_snprintf(last->bssid, sizeof(last->bssid),
+ "%s", buf + 13);
+ if (os_snprintf_error(sizeof(last->bssid), res))
+ break;
continue;
}
if (!last)
continue;
if (strncmp(buf, "uri=", 4) == 0) {
- snprintf(last->url, sizeof(last->url), "%s", buf + 4);
+ res = os_snprintf(last->url, sizeof(last->url),
+ "%s", buf + 4);
+ if (os_snprintf_error(sizeof(last->url), res))
+ break;
continue;
}
@@ -2055,26 +2061,37 @@
}
if (strncmp(buf, "osu_ssid=", 9) == 0) {
- snprintf(last->osu_ssid, sizeof(last->osu_ssid),
- "%s", buf + 9);
+ res = os_snprintf(last->osu_ssid,
+ sizeof(last->osu_ssid),
+ "%s", buf + 9);
+ if (os_snprintf_error(sizeof(last->osu_ssid), res))
+ break;
continue;
}
if (strncmp(buf, "osu_ssid2=", 10) == 0) {
- snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
- "%s", buf + 10);
+ res = os_snprintf(last->osu_ssid2,
+ sizeof(last->osu_ssid2),
+ "%s", buf + 10);
+ if (os_snprintf_error(sizeof(last->osu_ssid2), res))
+ break;
continue;
}
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
- os_snprintf(last->osu_nai, sizeof(last->osu_nai),
- "%s", buf + 8);
+ res = os_snprintf(last->osu_nai, sizeof(last->osu_nai),
+ "%s", buf + 8);
+ if (os_snprintf_error(sizeof(last->osu_nai), res))
+ break;
continue;
}
if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
- os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
- "%s", buf + 9);
+ res = os_snprintf(last->osu_nai2,
+ sizeof(last->osu_nai2),
+ "%s", buf + 9);
+ if (os_snprintf_error(sizeof(last->osu_nai2), res))
+ break;
continue;
}
@@ -2087,8 +2104,14 @@
continue;
*pos++ = '\0';
txt = &last->friendly_name[last->friendly_name_count++];
- snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14);
- snprintf(txt->text, sizeof(txt->text), "%s", pos);
+ res = os_snprintf(txt->lang, sizeof(txt->lang),
+ "%s", buf + 14);
+ if (os_snprintf_error(sizeof(txt->lang), res))
+ break;
+ res = os_snprintf(txt->text, sizeof(txt->text),
+ "%s", pos);
+ if (os_snprintf_error(sizeof(txt->text), res))
+ break;
}
if (strncmp(buf, "desc=", 5) == 0) {
@@ -2100,8 +2123,14 @@
continue;
*pos++ = '\0';
txt = &last->serv_desc[last->serv_desc_count++];
- snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5);
- snprintf(txt->text, sizeof(txt->text), "%s", pos);
+ res = os_snprintf(txt->lang, sizeof(txt->lang),
+ "%s", buf + 5);
+ if (os_snprintf_error(sizeof(txt->lang), res))
+ break;
+ res = os_snprintf(txt->text, sizeof(txt->text),
+ "%s", pos);
+ if (os_snprintf_error(sizeof(txt->text), res))
+ break;
}
if (strncmp(buf, "icon=", 5) == 0) {
@@ -2124,23 +2153,30 @@
if (!end)
continue;
*end = '\0';
- snprintf(icon->lang, sizeof(icon->lang), "%s", pos);
+ res = os_snprintf(icon->lang, sizeof(icon->lang),
+ "%s", pos);
+ if (os_snprintf_error(sizeof(icon->lang), res))
+ break;
pos = end + 1;
end = strchr(pos, ':');
if (end)
*end = '\0';
- snprintf(icon->mime_type, sizeof(icon->mime_type),
- "%s", pos);
- if (!pos)
+ res = os_snprintf(icon->mime_type,
+ sizeof(icon->mime_type), "%s", pos);
+ if (os_snprintf_error(sizeof(icon->mime_type), res))
+ break;
+ if (!end)
continue;
pos = end + 1;
end = strchr(pos, ':');
if (end)
*end = '\0';
- snprintf(icon->filename, sizeof(icon->filename),
- "%s", pos);
+ res = os_snprintf(icon->filename,
+ sizeof(icon->filename), "%s", pos);
+ if (os_snprintf_error(sizeof(icon->filename), res))
+ break;
continue;
}
}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index faaedbf..8ee2e04 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -420,19 +420,24 @@
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
- wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
+ wpa_printf(MSG_INFO,
+ "ACS: Survey for freq %d is missing noise floor",
+ survey->freq);
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
- wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
+ wpa_printf(MSG_INFO,
+ "ACS: Survey for freq %d is missing channel time",
+ survey->freq);
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
!(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
wpa_printf(MSG_INFO,
- "ACS: Survey is missing RX and busy time (at least one is required)");
+ "ACS: Survey for freq %d is missing RX and busy time (at least one is required)",
+ survey->freq);
return 0;
}
@@ -553,6 +558,10 @@
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
+ if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
+ iface->conf->country[2] == 0x4f)
+ continue;
+
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -687,6 +696,10 @@
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
+ if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
+ iface->conf->country[2] == 0x4f)
+ continue;
+
if (!chan_bw_allowed(chan, bw, 1, 1)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: BW %u is not supported",
@@ -710,7 +723,7 @@
if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
(iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
if (hostapd_get_oper_chwidth(iface->conf) ==
- CHANWIDTH_80MHZ &&
+ CONF_OPER_CHWIDTH_80MHZ &&
!acs_usable_bw80_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth",
@@ -719,7 +732,7 @@
}
if (hostapd_get_oper_chwidth(iface->conf) ==
- CHANWIDTH_160MHZ &&
+ CONF_OPER_CHWIDTH_160MHZ &&
!acs_usable_bw160_chan(chan)) {
wpa_printf(MSG_DEBUG,
"ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth",
@@ -873,12 +886,14 @@
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
n_chans = 4;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
n_chans = 8;
break;
+ default:
+ break;
}
}
@@ -915,13 +930,13 @@
wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
offset = 2 * iface->conf->secondary_channel;
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
offset = 6;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
offset = 14;
break;
default:
@@ -992,6 +1007,15 @@
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax)
acs_adjust_center_freq(iface);
+ err = hostapd_select_hw_mode(iface);
+ if (err) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Could not (err: %d) select hw_mode for freq=%d channel=%d",
+ err, iface->freq, iface->conf->channel);
+ err = -1;
+ goto fail;
+ }
+
err = 0;
fail:
/*
@@ -1066,6 +1090,10 @@
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
+ if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
+ iface->conf->country[2] == 0x4f)
+ continue;
+
*freq++ = chan->freq;
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index db86a76..b73aae2 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -482,6 +482,7 @@
struct sae_password_entry *pw;
if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) &&
+ !wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt) &&
!hostapd_sae_pk_in_use(conf)) ||
conf->sae_pwe == 3 ||
!wpa_key_mgmt_sae(conf->wpa_key_mgmt))
@@ -949,6 +950,8 @@
#ifdef CONFIG_DPP
os_free(conf->dpp_name);
os_free(conf->dpp_mud_url);
+ os_free(conf->dpp_extra_conf_req_name);
+ os_free(conf->dpp_extra_conf_req_value);
os_free(conf->dpp_connector);
wpabuf_free(conf->dpp_netaccesskey);
wpabuf_free(conf->dpp_csign);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b97d49c..268829a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -755,12 +755,15 @@
#ifdef CONFIG_DPP
char *dpp_name;
char *dpp_mud_url;
+ char *dpp_extra_conf_req_name;
+ char *dpp_extra_conf_req_value;
char *dpp_connector;
struct wpabuf *dpp_netaccesskey;
unsigned int dpp_netaccesskey_expiry;
struct wpabuf *dpp_csign;
#ifdef CONFIG_DPP2
struct dpp_controller_conf *dpp_controller;
+ int dpp_relay_port;
int dpp_configurator_connectivity;
int dpp_pfs;
#endif /* CONFIG_DPP2 */
@@ -1048,7 +1051,7 @@
u32 vht_capab;
int ieee80211ac;
int require_vht;
- u8 vht_oper_chwidth;
+ enum oper_chan_width vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
u8 ht40_plus_minus_allowed;
@@ -1094,7 +1097,7 @@
struct he_operation he_op;
struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
struct spatial_reuse spr;
- u8 he_oper_chwidth;
+ enum oper_chan_width he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
u8 he_6ghz_max_mpdu;
@@ -1132,7 +1135,7 @@
int ieee80211be;
#ifdef CONFIG_IEEE80211BE
- u8 eht_oper_chwidth;
+ enum oper_chan_width eht_oper_chwidth;
u8 eht_oper_centr_freq_seg0_idx;
struct eht_phy_capabilities_info eht_phy_capab;
#endif /* CONFIG_IEEE80211BE */
@@ -1144,7 +1147,8 @@
};
-static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
+static inline enum oper_chan_width
+hostapd_get_oper_chwidth(struct hostapd_config *conf)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
@@ -1158,11 +1162,14 @@
}
static inline void
-hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
+hostapd_set_oper_chwidth(struct hostapd_config *conf,
+ enum oper_chan_width oper_chwidth)
{
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
conf->eht_oper_chwidth = oper_chwidth;
+ if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
+ oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
@@ -1192,6 +1199,9 @@
#ifdef CONFIG_IEEE80211BE
if (conf->ieee80211be)
conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+ if (center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4)
+ oper_centr_freq_seg0_idx +=
+ conf->channel > oper_centr_freq_seg0_idx ? 16 : -16;
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8af7a0e..b9fd920 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -75,6 +75,14 @@
*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
+#ifdef NEED_AP_MLME
+ pos = buf;
+ pos = hostapd_eid_rm_enabled_capab(hapd, pos, sizeof(buf));
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0 ||
+ add_buf_data(&proberesp, buf, pos - buf) < 0)
+ goto fail;
+#endif /* NEED_AP_MLME */
+
pos = buf;
pos = hostapd_eid_time_adv(hapd, pos);
if (add_buf_data(&beacon, buf, pos - buf) < 0)
@@ -978,13 +986,16 @@
hapd->iface->conf->ieee80211ax ||
hapd->iface->conf->ieee80211ac) &&
params.ht40_enabled) {
- u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
+ enum oper_chan_width oper_chwidth;
- if (oper_chwidth == CHANWIDTH_80MHZ)
+ oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
+ if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
params.ch_width = 80;
- else if (oper_chwidth == CHANWIDTH_160MHZ ||
- oper_chwidth == CHANWIDTH_80P80MHZ)
+ else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
+ oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
params.ch_width = 160;
+ else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
+ params.ch_width = 320;
}
if (hapd->iface->conf->op_class)
@@ -1013,3 +1024,30 @@
return 0;
return hapd->driver->dpp_listen(hapd->drv_priv, enable);
}
+
+
+#ifdef CONFIG_PASN
+int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
+ const u8 *own_addr, const u8 *peer_addr,
+ u32 cipher, u8 tk_len, const u8 *tk,
+ u8 ltf_keyseed_len,
+ const u8 *ltf_keyseed, u32 action)
+{
+ struct secure_ranging_params params;
+
+ if (!hapd->driver || !hapd->driver->set_secure_ranging_ctx)
+ return 0;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.own_addr = own_addr;
+ params.peer_addr = peer_addr;
+ params.cipher = cipher;
+ params.tk_len = tk_len;
+ params.tk = tk;
+ params.ltf_keyseed_len = ltf_keyseed_len;
+ params.ltf_keyseed = ltf_keyseed;
+ params.action = action;
+
+ return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, ¶ms);
+}
+#endif /* CONFIG_PASN */
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index b4fb766..93b2244 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -138,6 +138,11 @@
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
+int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd,
+ const u8 *own_addr, const u8 *addr,
+ u32 cipher, u8 key_len, const u8 *key,
+ u8 ltf_keyseed_len,
+ const u8 *ltf_keyseed, u32 action);
#include "drivers/driver.h"
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index eaa4033..8676570 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -464,7 +464,8 @@
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
const struct ieee80211_mgmt *req,
- int is_p2p, size_t *resp_len)
+ int is_p2p, size_t *resp_len,
+ bool bcast_probe_resp)
{
struct ieee80211_mgmt *resp;
u8 *pos, *epos, *csa_pos;
@@ -531,6 +532,9 @@
WLAN_FC_STYPE_PROBE_RESP);
if (req)
os_memcpy(resp->da, req->sa, ETH_ALEN);
+ else if (bcast_probe_resp)
+ os_memset(resp->da, 0xff, ETH_ALEN);
+
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
@@ -1141,7 +1145,7 @@
" signal=%d", MAC2STR(mgmt->sa), ssi_signal);
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
- &resp_len);
+ &resp_len, false);
if (resp == NULL)
return;
@@ -1210,7 +1214,7 @@
"this");
/* Generate a Probe Response template for the non-P2P case */
- return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
+ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false);
}
#endif /* NEED_AP_MLME */
@@ -1228,7 +1232,8 @@
hapd->conf->unsol_bcast_probe_resp_interval;
return hostapd_gen_probe_resp(hapd, NULL, 0,
- ¶ms->unsol_bcast_probe_resp_tmpl_len);
+ ¶ms->unsol_bcast_probe_resp_tmpl_len,
+ true);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1275,22 +1280,24 @@
}
} else {
switch (hostapd_get_oper_chwidth(hapd->iconf)) {
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
mcs_nss_size += 4;
/* fallthrough */
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
mcs_nss_size += 4;
chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
chwidth = FD_CAP_BSS_CHWIDTH_80;
break;
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (hapd->iconf->secondary_channel)
chwidth = FD_CAP_BSS_CHWIDTH_40;
else
chwidth = FD_CAP_BSS_CHWIDTH_20;
break;
+ default:
+ break;
}
#ifdef CONFIG_IEEE80211AX
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 29b41f5..ac8f6fa 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1060,7 +1060,8 @@
if (sscanf(pos, "%d", &expiration) != 1)
return NULL;
- return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
+ return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN,
+ WPA_KEY_MGMT_SAE, pmkid, expiration);
}
#endif /* CONFIG_MESH */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index e46dd7e..7f31f28 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -50,15 +50,15 @@
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
n_chans = 4;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
n_chans = 8;
break;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
n_chans = 4;
*seg1 = 4;
break;
@@ -281,6 +281,10 @@
if (chan->max_tx_power < iface->conf->min_tx_power)
continue;
+ if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) &&
+ iface->conf->country[2] == 0x4f)
+ continue;
+
if (ret_chan && idx == channel_idx) {
wpa_printf(MSG_DEBUG, "Selected channel %d (%d)",
chan->freq, chan->chan);
@@ -311,7 +315,7 @@
*oper_centr_freq_seg1_idx = 0;
switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (secondary_channel == 1)
*oper_centr_freq_seg0_idx = chan->chan + 2;
else if (secondary_channel == -1)
@@ -319,13 +323,13 @@
else
*oper_centr_freq_seg0_idx = chan->chan;
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 14;
break;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
*oper_centr_freq_seg0_idx = chan->chan + 6;
*oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6;
break;
@@ -361,17 +365,17 @@
/* VHT/HE */
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
switch (hostapd_get_oper_chwidth(iface->conf)) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 6;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 14;
break;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
channel_no = hostapd_get_oper_centr_freq_seg0_idx(
iface->conf) - 6;
chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx(
@@ -555,7 +559,8 @@
*secondary_channel = 0;
/* Get secondary channel for HT80P80 */
- if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) {
+ if (hostapd_get_oper_chwidth(iface->conf) ==
+ CONF_OPER_CHWIDTH_80P80MHZ) {
if (num_available_chandefs <= 1) {
wpa_printf(MSG_ERROR,
"only 1 valid chan, can't support 80+80");
@@ -1220,7 +1225,7 @@
int oper_chwidth;
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
- if (oper_chwidth == CHANWIDTH_USE_HT)
+ if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
break;
*channel_type = DFS_AVAILABLE;
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index d4cbed8..32ddb3b 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -15,11 +15,13 @@
#include "common/dpp.h"
#include "common/gas.h"
#include "common/wpa_ctrl.h"
+#include "crypto/random.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
#include "gas_query_ap.h"
#include "gas_serv.h"
#include "wpa_auth.h"
+#include "beacon.h"
#include "dpp_hostapd.h"
@@ -278,19 +280,37 @@
}
+static void hostapd_dpp_pkex_clear_code(struct hostapd_data *hapd)
+{
+ if (!hapd->dpp_pkex_code && !hapd->dpp_pkex_identifier)
+ return;
+
+ /* Delete PKEX code and identifier on successful completion of
+ * PKEX. We are not supposed to reuse these without being
+ * explicitly requested to perform PKEX again. */
+ wpa_printf(MSG_DEBUG, "DPP: Delete PKEX code/identifier");
+ os_free(hapd->dpp_pkex_code);
+ hapd->dpp_pkex_code = NULL;
+ os_free(hapd->dpp_pkex_identifier);
+ hapd->dpp_pkex_identifier = NULL;
+}
+
+
#ifdef CONFIG_DPP2
static int hostapd_dpp_pkex_done(void *ctx, void *conn,
struct dpp_bootstrap_info *peer_bi)
{
struct hostapd_data *hapd = ctx;
- const char *cmd = hapd->dpp_pkex_auth_cmd;
+ char cmd[500];
const char *pos;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
struct dpp_bootstrap_info *own_bi = NULL;
struct dpp_authentication *auth;
- if (!cmd)
- cmd = "";
+ hostapd_dpp_pkex_clear_code(hapd);
+
+ os_snprintf(cmd, sizeof(cmd), " peer=%u %s", peer_bi->id,
+ hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
cmd);
@@ -342,6 +362,9 @@
return dpp_tcp_auth(hapd->iface->interfaces->dpp, conn, auth,
hapd->conf->dpp_name, DPP_NETROLE_AP,
+ hapd->conf->dpp_mud_url,
+ hapd->conf->dpp_extra_conf_req_name,
+ hapd->conf->dpp_extra_conf_req_value,
hostapd_dpp_process_conf_obj, NULL);
}
#endif /* CONFIG_DPP2 */
@@ -362,7 +385,7 @@
hapd->dpp_pkex = NULL;
pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr,
hapd->dpp_pkex_identifier,
- hapd->dpp_pkex_code, v2);
+ hapd->dpp_pkex_code, hapd->dpp_pkex_code_len, v2);
if (!pkex)
return -1;
pkex->forced_ver = ver != PKEX_VER_AUTO;
@@ -832,7 +855,17 @@
}
addr = get_param(cmd, " tcp_addr=");
- if (addr) {
+ if (addr && os_strcmp(addr, "from-uri") == 0) {
+ os_free(addr);
+ if (!peer_bi->host) {
+ wpa_printf(MSG_INFO,
+ "DPP: TCP address not available in peer URI");
+ return -1;
+ }
+ tcp = 1;
+ os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr));
+ tcp_port = peer_bi->port;
+ } else if (addr) {
int res;
res = hostapd_parse_ip_addr(addr, &ipaddr);
@@ -917,7 +950,10 @@
if (tcp)
return dpp_tcp_init(hapd->iface->interfaces->dpp, auth,
&ipaddr, tcp_port, hapd->conf->dpp_name,
- DPP_NETROLE_AP, hapd->msg_ctx, hapd,
+ DPP_NETROLE_AP, hapd->conf->dpp_mud_url,
+ hapd->conf->dpp_extra_conf_req_name,
+ hapd->conf->dpp_extra_conf_req_value,
+ hapd->msg_ctx, hapd,
hostapd_dpp_process_conf_obj, NULL);
#endif /* CONFIG_DPP2 */
@@ -965,6 +1001,27 @@
}
+#ifdef CONFIG_DPP2
+static void
+hostapd_dpp_relay_needs_controller(struct hostapd_data *hapd, const u8 *src,
+ enum dpp_public_action_frame_type type)
+{
+ struct os_reltime now;
+
+ if (!hapd->conf->dpp_relay_port)
+ return;
+
+ os_get_reltime(&now);
+ if (hapd->dpp_relay_last_needs_ctrl.sec &&
+ !os_reltime_expired(&now, &hapd->dpp_relay_last_needs_ctrl, 60))
+ return;
+ hapd->dpp_relay_last_needs_ctrl = now;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RELAY_NEEDS_CONTROLLER
+ MACSTR " %u", MAC2STR(src), type);
+}
+#endif /* CONFIG_DPP2 */
+
+
static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
@@ -1013,6 +1070,8 @@
src, hdr, buf, len, freq, i_bootstrap,
r_bootstrap, hapd) == 0)
return;
+ hostapd_dpp_relay_needs_controller(hapd, src,
+ DPP_PA_AUTHENTICATION_REQ);
}
#endif /* CONFIG_DPP2 */
if (!own_bi) {
@@ -1021,6 +1080,21 @@
return;
}
+ if (own_bi->type == DPP_BOOTSTRAP_PKEX) {
+ if (!peer_bi || peer_bi->type != DPP_BOOTSTRAP_PKEX) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "No matching peer bootstrapping key found for PKEX - ignore message");
+ return;
+ }
+
+ if (os_memcmp(peer_bi->pubkey_hash, own_bi->peer_pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "Mismatching peer PKEX bootstrapping key - ignore message");
+ return;
+ }
+ }
+
if (hapd->dpp_auth) {
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Already in DPP authentication exchange - ignore new one");
@@ -1276,7 +1350,9 @@
buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name,
DPP_NETROLE_AP,
- hapd->conf->dpp_mud_url, NULL);
+ hapd->conf->dpp_mud_url, NULL,
+ hapd->conf->dpp_extra_conf_req_name,
+ hapd->conf->dpp_extra_conf_req_value);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -1440,11 +1516,53 @@
}
+#ifdef CONFIG_DPP3
+
+static bool hostapd_dpp_pb_active(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+
+ return ifaces && (ifaces->dpp_pb_time.sec ||
+ ifaces->dpp_pb_time.usec);
+}
+
+
+static void hostapd_dpp_remove_pb_hash(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+ int i;
+
+ if (!ifaces->dpp_pb_bi)
+ return;
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ struct dpp_pb_info *info = &ifaces->dpp_pb[i];
+
+ if (info->rx_time.sec == 0 && info->rx_time.usec == 0)
+ continue;
+ if (os_memcmp(info->hash, ifaces->dpp_pb_resp_hash,
+ SHA256_MAC_LEN) == 0) {
+ /* Allow a new push button session to be established
+ * immediately without the successfully completed
+ * session triggering session overlap. */
+ info->rx_time.sec = 0;
+ info->rx_time.usec = 0;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Removed PB hash from session overlap detection due to successfully completed provisioning");
+ }
+ }
+}
+
+#endif /* CONFIG_DPP3 */
+
+
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status;
+#ifdef CONFIG_DPP3
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+#endif /* CONFIG_DPP3 */
wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
MAC2STR(src));
@@ -1465,7 +1583,8 @@
if (status == DPP_STATUS_OK && auth->send_conn_status) {
wpa_msg(hapd->msg_ctx, MSG_INFO,
- DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ DPP_EVENT_CONF_SENT "wait_conn_status=1 conf_status=%d",
+ auth->conf_resp_status);
wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
hapd, NULL);
@@ -1481,13 +1600,28 @@
hostapd_drv_send_action_cancel_wait(hapd);
hostapd_dpp_listen_stop(hapd);
if (status == DPP_STATUS_OK)
- wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT
+ "conf_status=%d", auth->conf_resp_status);
else
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(auth);
hapd->dpp_auth = NULL;
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
+#ifdef CONFIG_DPP3
+ if (!ifaces->dpp_pb_result_indicated && hostapd_dpp_pb_active(hapd)) {
+ if (status == DPP_STATUS_OK)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "success");
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "no-configuration-available");
+ ifaces->dpp_pb_result_indicated = true;
+ if (status == DPP_STATUS_OK)
+ hostapd_dpp_remove_pb_hash(hapd);
+ hostapd_dpp_push_button_stop(hapd);
+ }
+#endif /* CONFIG_DPP3 */
}
@@ -1559,6 +1693,8 @@
return;
wpa_printf(MSG_DEBUG,
"DPP: No matching bootstrapping information found");
+ hostapd_dpp_relay_needs_controller(
+ hapd, src, DPP_PA_PRESENCE_ANNOUNCEMENT);
return;
}
@@ -1649,6 +1785,8 @@
return;
wpa_printf(MSG_DEBUG,
"DPP: No matching Configurator information found");
+ hostapd_dpp_relay_needs_controller(
+ hapd, src, DPP_PA_RECONFIG_ANNOUNCEMENT);
return;
}
@@ -1883,6 +2021,25 @@
}
+static bool hapd_dpp_connector_available(struct hostapd_data *hapd)
+{
+ if (!hapd->wpa_auth ||
+ !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
+ !(hapd->conf->wpa & WPA_PROTO_RSN)) {
+ wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
+ return false;
+ }
+
+ if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
+ !hapd->conf->dpp_csign) {
+ wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
+ return false;
+ }
+
+ return true;
+}
+
+
static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
const u8 *src,
const u8 *buf, size_t len,
@@ -1896,20 +2053,12 @@
int expiration;
enum dpp_status_error res;
+ os_memset(&intro, 0, sizeof(intro));
+
wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
MAC2STR(src));
- if (!hapd->wpa_auth ||
- !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
- !(hapd->conf->wpa & WPA_PROTO_RSN)) {
- wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
+ if (!hapd_dpp_connector_available(hapd))
return;
- }
-
- if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
- !hapd->conf->dpp_csign) {
- wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
- return;
- }
os_get_time(&now);
@@ -1944,7 +2093,7 @@
wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in internal failure (peer "
MACSTR ")", MAC2STR(src));
- return;
+ goto done;
}
if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO,
@@ -1952,7 +2101,7 @@
MACSTR " status %d)", MAC2STR(src), res);
hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
res);
- return;
+ goto done;
}
#ifdef CONFIG_DPP3
@@ -1972,7 +2121,7 @@
hostapd_dpp_send_peer_disc_resp(hapd, src, freq,
trans_id[0],
DPP_STATUS_NO_MATCH);
- return;
+ goto done;
}
}
#endif /* CONFIG_DPP3 */
@@ -1988,11 +2137,13 @@
intro.pmkid, expiration,
WPA_KEY_MGMT_DPP) < 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
- return;
+ goto done;
}
hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
DPP_STATUS_OK);
+done:
+ dpp_peer_intro_deinit(&intro);
}
@@ -2026,6 +2177,15 @@
goto try_relay;
}
+#ifdef CONFIG_DPP2
+ if (dpp_controller_is_own_pkex_req(hapd->iface->interfaces->dpp,
+ buf, len)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX Exchange Request is from local Controller - ignore request");
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
if (hapd->dpp_pkex) {
/* TODO: Support parallel operations */
wpa_printf(MSG_DEBUG,
@@ -2038,6 +2198,7 @@
hapd->own_addr, src,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code,
+ hapd->dpp_pkex_code_len,
buf, len, v2);
if (!hapd->dpp_pkex) {
wpa_printf(MSG_DEBUG,
@@ -2064,9 +2225,14 @@
try_relay:
#ifdef CONFIG_DPP2
- if (v2)
- dpp_relay_rx_action(hapd->iface->interfaces->dpp,
- src, hdr, buf, len, freq, NULL, NULL, hapd);
+ if (v2 && dpp_relay_rx_action(hapd->iface->interfaces->dpp,
+ src, hdr, buf, len, freq, NULL, NULL,
+ hapd) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Relay available for the message");
+ hostapd_dpp_relay_needs_controller(hapd, src,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ }
#else /* CONFIG_DPP2 */
wpa_printf(MSG_DEBUG, "DPP: No relay functionality included - skip");
#endif /* CONFIG_DPP2 */
@@ -2153,6 +2319,7 @@
wpabuf_head(msg), wpabuf_len(msg));
wpabuf_free(msg);
+ hostapd_dpp_pkex_clear_code(hapd);
bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
if (!bi)
return;
@@ -2165,6 +2332,7 @@
const u8 *hdr, const u8 *buf, size_t len,
unsigned int freq)
{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
int res;
struct dpp_bootstrap_info *bi;
struct dpp_pkex *pkex = hapd->dpp_pkex;
@@ -2184,11 +2352,34 @@
return;
}
- bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq);
+ hostapd_dpp_pkex_clear_code(hapd);
+ bi = dpp_pkex_finish(ifaces->dpp, pkex, src, freq);
if (!bi)
return;
hapd->dpp_pkex = NULL;
+#ifdef CONFIG_DPP3
+ if (ifaces->dpp_pb_bi &&
+ os_memcmp(bi->pubkey_hash_chirp, ifaces->dpp_pb_resp_hash,
+ SHA256_MAC_LEN) != 0) {
+ char id[20];
+
+ wpa_printf(MSG_INFO,
+ "DPP: Peer bootstrap key from PKEX does not match PB announcement hash");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB announcement",
+ ifaces->dpp_pb_resp_hash, SHA256_MAC_LEN);
+
+ os_snprintf(id, sizeof(id), "%u", bi->id);
+ dpp_bootstrap_remove(ifaces->dpp, id);
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
bi->id,
hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : "");
@@ -2203,6 +2394,534 @@
}
+#ifdef CONFIG_DPP3
+
+static void hostapd_dpp_pb_pkex_init(struct hostapd_data *hapd,
+ unsigned int freq, const u8 *src,
+ const u8 *r_hash)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+ char ssid_hex[2 * SSID_MAX_LEN + 1], *pass_hex = NULL;
+ char cmd[300];
+ const char *password = NULL;
+ struct sae_password_entry *e;
+ int conf_id = -1;
+ bool sae = false, psk = false;
+ size_t len;
+
+ if (hapd->dpp_pkex) {
+ wpa_printf(MSG_DEBUG,
+ "PDP: Sending previously generated PKEX Exchange Request to "
+ MACSTR, MAC2STR(src));
+ msg = hapd->dpp_pkex->exchange_req;
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiate PKEX for push button with "
+ MACSTR, MAC2STR(src));
+
+ hapd->dpp_pkex_bi = ifaces->dpp_pb_bi;
+ os_memcpy(ifaces->dpp_pb_resp_hash, r_hash, SHA256_MAC_LEN);
+
+ pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr,
+ "PBPKEX", (const char *) ifaces->dpp_pb_c_nonce,
+ ifaces->dpp_pb_bi->curve->nonce_len,
+ true);
+ if (!pkex) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ pkex->freq = freq;
+
+ hapd->dpp_pkex = pkex;
+ msg = hapd->dpp_pkex->exchange_req;
+
+ if (ifaces->dpp_pb_cmd) {
+ /* Use the externally provided configuration */
+ os_free(hapd->dpp_pkex_auth_cmd);
+ len = 30 + os_strlen(ifaces->dpp_pb_cmd);
+ hapd->dpp_pkex_auth_cmd = os_malloc(len);
+ if (!hapd->dpp_pkex_auth_cmd) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ os_snprintf(hapd->dpp_pkex_auth_cmd, len, " own=%d %s",
+ hapd->dpp_pkex_bi->id, ifaces->dpp_pb_cmd);
+ goto send_frame;
+ }
+
+ /* Build config based on the current AP configuration */
+ wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex),
+ (const u8 *) hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
+ /* TODO: If a local Configurator has been enabled, allow a
+ * DPP AKM credential to be provisioned by setting conf_id. */
+ }
+
+ if (hapd->conf->wpa & WPA_PROTO_RSN) {
+ psk = hapd->conf->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256);
+#ifdef CONFIG_SAE
+ sae = hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE;
+#endif /* CONFIG_SAE */
+ }
+
+#ifdef CONFIG_SAE
+ for (e = hapd->conf->sae_passwords; sae && e && !password;
+ e = e->next) {
+ if (e->identifier || !is_broadcast_ether_addr(e->peer_addr))
+ continue;
+ password = e->password;
+ }
+#endif /* CONFIG_SAE */
+ if (!password && hapd->conf->ssid.wpa_passphrase_set &&
+ hapd->conf->ssid.wpa_passphrase)
+ password = hapd->conf->ssid.wpa_passphrase;
+ if (password) {
+ len = 2 * os_strlen(password) + 1;
+ pass_hex = os_malloc(len);
+ if (!pass_hex) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ wpa_snprintf_hex(pass_hex, len, (const u8 *) password,
+ os_strlen(password));
+ }
+
+ if (conf_id > 0 && sae && psk && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-dpp+psk+sae configurator=%d ssid=%s pass=%s",
+ conf_id, ssid_hex, pass_hex);
+ } else if (conf_id > 0 && sae && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-dpp+sae configurator=%d ssid=%s pass=%s",
+ conf_id, ssid_hex, pass_hex);
+ } else if (conf_id > 0) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-dpp configurator=%d ssid=%s",
+ conf_id, ssid_hex);
+ } if (sae && psk && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-psk+sae ssid=%s pass=%s",
+ ssid_hex, pass_hex);
+ } else if (sae && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-sae ssid=%s pass=%s",
+ ssid_hex, pass_hex);
+ } else if (psk && pass_hex) {
+ os_snprintf(cmd, sizeof(cmd),
+ "conf=sta-psk ssid=%s pass=%s",
+ ssid_hex, pass_hex);
+ } else {
+ wpa_printf(MSG_INFO,
+ "DPP: Unsupported AP configuration for push button");
+ str_clear_free(pass_hex);
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ str_clear_free(pass_hex);
+
+ os_free(hapd->dpp_pkex_auth_cmd);
+ len = 30 + os_strlen(cmd);
+ hapd->dpp_pkex_auth_cmd = os_malloc(len);
+ if (hapd->dpp_pkex_auth_cmd)
+ os_snprintf(hapd->dpp_pkex_auth_cmd, len, " own=%d %s",
+ hapd->dpp_pkex_bi->id, cmd);
+ forced_memzero(cmd, sizeof(cmd));
+ if (!hapd->dpp_pkex_auth_cmd) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+
+send_frame:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ hostapd_drv_send_action(hapd, pkex->freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ pkex->exch_req_wait_time = 2000;
+ pkex->exch_req_tries = 1;
+}
+
+
+static void
+hostapd_dpp_rx_pb_presence_announcement(struct hostapd_data *hapd,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+ const u8 *r_hash;
+ u16 r_hash_len;
+ unsigned int i;
+ bool found = false;
+ struct dpp_pb_info *info, *tmp;
+ struct os_reltime now, age;
+ struct wpabuf *msg;
+
+ if (!ifaces)
+ return;
+
+ os_get_reltime(&now);
+ wpa_printf(MSG_DEBUG, "DPP: Push Button Presence Announcement from "
+ MACSTR, MAC2STR(src));
+
+ r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_hash_len);
+ if (!r_hash || r_hash_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_hash, r_hash_len);
+
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ info = &ifaces->dpp_pb[i];
+ if ((info->rx_time.sec == 0 && info->rx_time.usec == 0) ||
+ os_memcmp(r_hash, info->hash, SHA256_MAC_LEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Active push button Enrollee already known");
+ found = true;
+ info->rx_time = now;
+ }
+
+ if (!found) {
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ tmp = &ifaces->dpp_pb[i];
+ if (tmp->rx_time.sec == 0 && tmp->rx_time.usec == 0)
+ continue;
+
+ if (os_reltime_expired(&now, &tmp->rx_time, 120)) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Push button Enrollee hash expired",
+ tmp->hash, SHA256_MAC_LEN);
+ tmp->rx_time.sec = 0;
+ tmp->rx_time.usec = 0;
+ continue;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Push button session overlap with hash",
+ tmp->hash, SHA256_MAC_LEN);
+ if (!ifaces->dpp_pb_result_indicated &&
+ hostapd_dpp_pb_active(hapd)) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_PB_RESULT "session-overlap");
+ ifaces->dpp_pb_result_indicated = true;
+ }
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+
+ /* Replace the oldest entry */
+ info = &ifaces->dpp_pb[0];
+ for (i = 1; i < DPP_PB_INFO_COUNT; i++) {
+ tmp = &ifaces->dpp_pb[i];
+ if (os_reltime_before(&tmp->rx_time, &info->rx_time))
+ info = tmp;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: New active push button Enrollee");
+ os_memcpy(info->hash, r_hash, SHA256_MAC_LEN);
+ info->rx_time = now;
+ }
+
+ if (!hostapd_dpp_pb_active(hapd)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Discard message since own push button has not been pressed");
+ return;
+ }
+
+ if (ifaces->dpp_pb_announce_time.sec == 0 &&
+ ifaces->dpp_pb_announce_time.usec == 0) {
+ /* Start a wait before allowing PKEX to be initiated */
+ ifaces->dpp_pb_announce_time = now;
+ }
+
+ if (!ifaces->dpp_pb_bi) {
+ int res;
+
+ res = dpp_bootstrap_gen(ifaces->dpp, "type=pkex");
+ if (res < 0)
+ return;
+ ifaces->dpp_pb_bi = dpp_bootstrap_get_id(ifaces->dpp, res);
+ if (!ifaces->dpp_pb_bi)
+ return;
+
+ if (random_get_bytes(ifaces->dpp_pb_c_nonce,
+ ifaces->dpp_pb_bi->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate C-nonce");
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+ }
+
+ /* Skip the response if one was sent within last 50 ms since the
+ * Enrollee is going to send out at least three announcement messages.
+ */
+ os_reltime_sub(&now, &ifaces->dpp_pb_last_resp, &age);
+ if (age.sec == 0 && age.usec < 50000) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Skip Push Button Presence Announcement Response frame immediately after having sent one");
+ return;
+ }
+
+ msg = dpp_build_pb_announcement_resp(
+ ifaces->dpp_pb_bi, r_hash, ifaces->dpp_pb_c_nonce,
+ ifaces->dpp_pb_bi->curve->nonce_len);
+ if (!msg) {
+ hostapd_dpp_push_button_stop(hapd);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send Push Button Presence Announcement Response to "
+ MACSTR, MAC2STR(src));
+ ifaces->dpp_pb_last_resp = now;
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+
+ if (os_reltime_expired(&now, &ifaces->dpp_pb_announce_time, 15))
+ hostapd_dpp_pb_pkex_init(hapd, freq, src, r_hash);
+}
+
+
+static void
+hostapd_dpp_rx_priv_peer_intro_query(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *trans_id, *version;
+ u16 trans_id_len, version_len;
+ struct wpabuf *msg;
+ u8 ver = DPP_VERSION;
+ int conn_ver;
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Query from "
+ MACSTR, MAC2STR(src));
+
+ if (!hapd_dpp_connector_available(hapd))
+ return;
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ return;
+ }
+
+ version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (!version || version_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Protocol Version");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Transaction ID %u, Version %u",
+ trans_id[0], version[0]);
+
+ len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector);
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_NOTIFY, len);
+ if (!msg)
+ return;
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, trans_id[0]);
+
+ /* Protocol Version */
+ conn_ver = dpp_get_connector_version(hapd->conf->dpp_connector);
+ if (conn_ver > 0 && ver != conn_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Use Connector version %d instead of current protocol version %d",
+ conn_ver, ver);
+ ver = conn_ver;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, ver);
+
+ /* DPP Connector */
+ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector));
+ wpabuf_put_str(msg, hapd->conf->dpp_connector);
+
+ wpa_printf(MSG_DEBUG, "DPP: Send Private Peer Introduction Notify to "
+ MACSTR, MAC2STR(src));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PRIV_PEER_INTRO_NOTIFY);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+}
+
+
+static void
+hostapd_dpp_rx_priv_peer_intro_update(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct crypto_ec_key *own_key;
+ const struct dpp_curve_params *curve;
+ enum hpke_kem_id kem_id;
+ enum hpke_kdf_id kdf_id;
+ enum hpke_aead_id aead_id;
+ const u8 *aad = hdr;
+ size_t aad_len = DPP_HDR_LEN;
+ struct wpabuf *pt;
+ const u8 *trans_id, *wrapped, *version, *connector;
+ u16 trans_id_len, wrapped_len, version_len, connector_len;
+ struct os_time now;
+ struct dpp_introduction intro;
+ os_time_t expire;
+ int expiration;
+ enum dpp_status_error res;
+
+ os_memset(&intro, 0, sizeof(intro));
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Update from "
+ MACSTR, MAC2STR(src));
+
+ if (!hapd_dpp_connector_available(hapd))
+ return;
+
+ os_get_time(&now);
+
+ if (hapd->conf->dpp_netaccesskey_expiry &&
+ (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
+ wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
+ return;
+ }
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ return;
+ }
+
+ wrapped = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_len);
+ if (!wrapped) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer did not include Wrapped Data");
+ return;
+ }
+
+ own_key = dpp_set_keypair(&curve,
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey));
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ return;
+ }
+
+ if (dpp_hpke_suite(curve->ike_group, &kem_id, &kdf_id, &aead_id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Unsupported curve %d",
+ curve->ike_group);
+ crypto_ec_key_deinit(own_key);
+ return;
+ }
+
+ pt = hpke_base_open(kem_id, kdf_id, aead_id, own_key, NULL, 0,
+ aad, aad_len, wrapped, wrapped_len);
+ crypto_ec_key_deinit(own_key);
+ if (!pt) {
+ wpa_printf(MSG_INFO, "DPP: Failed to decrypt Connector");
+ return;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE-Decrypted Wrapped Data", pt);
+
+ connector = dpp_get_attr(wpabuf_head(pt), wpabuf_len(pt),
+ DPP_ATTR_CONNECTOR, &connector_len);
+ if (!connector) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include its Connector");
+ goto done;
+ }
+
+ version = dpp_get_attr(wpabuf_head(pt), wpabuf_len(pt),
+ DPP_ATTR_PROTOCOL_VERSION, &version_len);
+ if (!version || version_len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Protocol Version");
+ goto done;
+ }
+
+ res = dpp_peer_intro(&intro, hapd->conf->dpp_connector,
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey),
+ wpabuf_head(hapd->conf->dpp_csign),
+ wpabuf_len(hapd->conf->dpp_csign),
+ connector, connector_len, &expire);
+ if (res == 255) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in internal failure (peer "
+ MACSTR ")", MAC2STR(src));
+ goto done;
+ }
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in failure (peer "
+ MACSTR " status %d)", MAC2STR(src), res);
+ goto done;
+ }
+
+ if (intro.peer_version && intro.peer_version >= 2) {
+ u8 attr_version = 1;
+
+ if (version && version_len >= 1)
+ attr_version = version[0];
+ if (attr_version != intro.peer_version) {
+ wpa_printf(MSG_INFO,
+ "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
+ intro.peer_version, attr_version);
+ goto done;
+ }
+ }
+
+ if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
+ expire = hapd->conf->dpp_netaccesskey_expiry;
+ if (expire)
+ expiration = expire - now.sec;
+ else
+ expiration = 0;
+
+ if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+ intro.pmkid, expiration,
+ WPA_KEY_MGMT_DPP) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
+ goto done;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction completed with "
+ MACSTR, MAC2STR(src));
+
+done:
+ dpp_peer_intro_deinit(&intro);
+ wpabuf_free(pt);
+}
+
+#endif /* CONFIG_DPP3 */
+
+
void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
const u8 *buf, size_t len, unsigned int freq)
{
@@ -2308,6 +3027,20 @@
freq);
break;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ case DPP_PA_PB_PRESENCE_ANNOUNCEMENT:
+ hostapd_dpp_rx_pb_presence_announcement(hapd, src, hdr,
+ buf, len, freq);
+ break;
+ case DPP_PA_PRIV_PEER_INTRO_QUERY:
+ hostapd_dpp_rx_priv_peer_intro_query(hapd, src, hdr,
+ buf, len, freq);
+ break;
+ case DPP_PA_PRIV_PEER_INTRO_UPDATE:
+ hostapd_dpp_rx_priv_peer_intro_update(hapd, src, hdr,
+ buf, len, freq);
+ break;
+#endif /* CONFIG_DPP3 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
@@ -2376,6 +3109,9 @@
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
{
struct dpp_authentication *auth = hapd->dpp_auth;
+#ifdef CONFIG_DPP3
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+#endif /* CONFIG_DPP3 */
if (!auth)
return;
@@ -2410,11 +3146,26 @@
hostapd_drv_send_action_cancel_wait(hapd);
if (ok)
- wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT
+ "conf_status=%d", auth->conf_resp_status);
else
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
+#ifdef CONFIG_DPP3
+ if (!ifaces->dpp_pb_result_indicated && hostapd_dpp_pb_active(hapd)) {
+ if (ok)
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "success");
+ else
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT
+ "could-not-connect");
+ ifaces->dpp_pb_result_indicated = true;
+ if (ok)
+ hostapd_dpp_remove_pb_hash(hapd);
+ hostapd_dpp_push_button_stop(hapd);
+ }
+#endif /* CONFIG_DPP3 */
}
@@ -2516,6 +3267,7 @@
hapd->dpp_pkex_code = os_strdup(pos + 6);
if (!hapd->dpp_pkex_code)
return -1;
+ hapd->dpp_pkex_code_len = os_strlen(hapd->dpp_pkex_code);
pos = os_strstr(cmd, " ver=");
if (pos) {
@@ -2564,7 +3316,7 @@
return -1;
}
- if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code)
+ if ((id_val != 0 && id_val != 1))
return -1;
/* TODO: Support multiple PKEX entries */
@@ -2588,6 +3340,9 @@
hapd->dpp_auth = NULL;
dpp_pkex_free(hapd->dpp_pkex);
hapd->dpp_pkex = NULL;
+#ifdef CONFIG_DPP3
+ hostapd_dpp_push_button_stop(hapd);
+#endif /* CONFIG_DPP3 */
}
@@ -2599,6 +3354,9 @@
struct hostapd_data *hapd = ctx;
u8 *buf;
+ if (freq == 0)
+ freq = hapd->iface->freq;
+
wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR " freq=%u",
MAC2STR(addr), freq);
buf = os_malloc(2 + len);
@@ -2631,6 +3389,7 @@
struct dpp_relay_config config;
os_memset(&config, 0, sizeof(config));
+ config.msg_ctx = hapd->msg_ctx;
config.cb_ctx = hapd;
config.tx = hostapd_dpp_relay_tx;
config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
@@ -2641,12 +3400,76 @@
&config) < 0)
return -1;
}
+
+ if (hapd->conf->dpp_relay_port)
+ dpp_relay_listen(hapd->iface->interfaces->dpp,
+ hapd->conf->dpp_relay_port,
+ &config);
#endif /* CONFIG_DPP2 */
return 0;
}
+#ifdef CONFIG_DPP2
+
+int hostapd_dpp_add_controller(struct hostapd_data *hapd, const char *cmd)
+{
+ struct dpp_relay_config config;
+ struct hostapd_ip_addr addr;
+ u8 pkhash[SHA256_MAC_LEN];
+ char *pos, *tmp;
+ int ret = -1;
+ bool prev_state, new_state;
+ struct dpp_global *dpp = hapd->iface->interfaces->dpp;
+
+ tmp = os_strdup(cmd);
+ if (!tmp)
+ goto fail;
+ pos = os_strchr(tmp, ' ');
+ if (!pos)
+ goto fail;
+ *pos++ = '\0';
+ if (hostapd_parse_ip_addr(tmp, &addr) < 0 ||
+ hexstr2bin(pos, pkhash, SHA256_MAC_LEN) < 0)
+ goto fail;
+
+ os_memset(&config, 0, sizeof(config));
+ config.msg_ctx = hapd->msg_ctx;
+ config.cb_ctx = hapd;
+ config.tx = hostapd_dpp_relay_tx;
+ config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx;
+ config.ipaddr = &addr;
+ config.pkhash = pkhash;
+ prev_state = dpp_relay_controller_available(dpp);
+ ret = dpp_relay_add_controller(dpp, &config);
+ new_state = dpp_relay_controller_available(dpp);
+ if (new_state != prev_state)
+ ieee802_11_update_beacons(hapd->iface);
+fail:
+ os_free(tmp);
+ return ret;
+}
+
+
+void hostapd_dpp_remove_controller(struct hostapd_data *hapd, const char *cmd)
+{
+ struct hostapd_ip_addr addr;
+ bool prev_state, new_state;
+ struct dpp_global *dpp = hapd->iface->interfaces->dpp;
+
+ if (hostapd_parse_ip_addr(cmd, &addr) < 0)
+ return;
+ prev_state = dpp_relay_controller_available(dpp);
+ dpp_relay_remove_controller(dpp, &addr);
+ new_state = dpp_relay_controller_available(dpp);
+ if (new_state != prev_state)
+ ieee802_11_update_beacons(hapd->iface);
+}
+
+#endif /* CONFIG_DPP2 */
+
+
int hostapd_dpp_init(struct hostapd_data *hapd)
{
hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE;
@@ -2681,11 +3504,14 @@
eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
NULL);
hostapd_dpp_chirp_stop(hapd);
- if (hapd->iface->interfaces)
+ if (hapd->iface->interfaces) {
+ dpp_relay_stop_listen(hapd->iface->interfaces->dpp);
dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd);
+ }
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_DPP3
eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL);
+ hostapd_dpp_push_button_stop(hapd);
#endif /* CONFIG_DPP3 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -2693,6 +3519,8 @@
hapd->dpp_pkex = NULL;
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = NULL;
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = NULL;
}
@@ -3065,3 +3893,84 @@
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+
+static void hostapd_dpp_push_button_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "DPP: Active push button mode expired");
+ hostapd_dpp_push_button_stop(hapd);
+}
+
+
+int hostapd_dpp_push_button(struct hostapd_data *hapd, const char *cmd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+
+ if (!ifaces || !ifaces->dpp)
+ return -1;
+ os_get_reltime(&ifaces->dpp_pb_time);
+ ifaces->dpp_pb_announce_time.sec = 0;
+ ifaces->dpp_pb_announce_time.usec = 0;
+ str_clear_free(ifaces->dpp_pb_cmd);
+ ifaces->dpp_pb_cmd = NULL;
+ if (cmd) {
+ ifaces->dpp_pb_cmd = os_strdup(cmd);
+ if (!ifaces->dpp_pb_cmd)
+ return -1;
+ }
+ eloop_register_timeout(100, 0, hostapd_dpp_push_button_expire,
+ hapd, NULL);
+
+ return 0;
+}
+
+
+void hostapd_dpp_push_button_stop(struct hostapd_data *hapd)
+{
+ struct hapd_interfaces *ifaces = hapd->iface->interfaces;
+
+ if (!ifaces || !ifaces->dpp)
+ return;
+ eloop_cancel_timeout(hostapd_dpp_push_button_expire, hapd, NULL);
+ if (hostapd_dpp_pb_active(hapd)) {
+ wpa_printf(MSG_DEBUG, "DPP: Stop active push button mode");
+ if (!ifaces->dpp_pb_result_indicated)
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ DPP_EVENT_PB_RESULT "failed");
+ }
+ ifaces->dpp_pb_time.sec = 0;
+ ifaces->dpp_pb_time.usec = 0;
+ dpp_pkex_free(hapd->dpp_pkex);
+ hapd->dpp_pkex = NULL;
+ os_free(hapd->dpp_pkex_auth_cmd);
+ hapd->dpp_pkex_auth_cmd = NULL;
+
+ if (ifaces->dpp_pb_bi) {
+ char id[20];
+
+ os_snprintf(id, sizeof(id), "%u", ifaces->dpp_pb_bi->id);
+ dpp_bootstrap_remove(ifaces->dpp, id);
+ ifaces->dpp_pb_bi = NULL;
+ }
+
+ ifaces->dpp_pb_result_indicated = false;
+
+ str_clear_free(ifaces->dpp_pb_cmd);
+ ifaces->dpp_pb_cmd = NULL;
+}
+
+#endif /* CONFIG_DPP3 */
+
+
+#ifdef CONFIG_DPP2
+bool hostapd_dpp_configurator_connectivity(struct hostapd_data *hapd)
+{
+ return hapd->conf->dpp_configurator_connectivity ||
+ (hapd->iface->interfaces &&
+ dpp_relay_controller_available(hapd->iface->interfaces->dpp));
+}
+#endif /* CONFIG_DPP2 */
diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h
index 264d3e4..55f1fce 100644
--- a/src/ap/dpp_hostapd.h
+++ b/src/ap/dpp_hostapd.h
@@ -45,5 +45,10 @@
int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd);
void hostapd_dpp_chirp_stop(struct hostapd_data *hapd);
void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi);
+int hostapd_dpp_push_button(struct hostapd_data *hapd, const char *cmd);
+void hostapd_dpp_push_button_stop(struct hostapd_data *hapd);
+bool hostapd_dpp_configurator_connectivity(struct hostapd_data *hapd);
+int hostapd_dpp_add_controller(struct hostapd_data *hapd, const char *cmd);
+void hostapd_dpp_remove_controller(struct hostapd_data *hapd, const char *cmd);
#endif /* DPP_HOSTAPD_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 643a273..b1cb31e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -340,6 +340,16 @@
}
#endif /* CONFIG_WPS */
+ if (check_sa_query_need(hapd, sta)) {
+ status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+ p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+ p - buf);
+ return 0;
+ }
+
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr,
@@ -420,16 +430,6 @@
goto fail;
}
- if (check_sa_query_need(hapd, sta)) {
- status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
-
- p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
-
- hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
- p - buf);
- return 0;
- }
-
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
else
@@ -838,6 +838,9 @@
case CHAN_WIDTH_160:
txt = "160";
break;
+ case CHAN_WIDTH_320:
+ txt = "320";
+ break;
default:
txt = NULL;
break;
@@ -891,19 +894,22 @@
switch (width) {
case CHAN_WIDTH_80:
- chwidth = CHANWIDTH_80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
- chwidth = CHANWIDTH_80P80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
+ break;
+ case CHAN_WIDTH_320:
+ chwidth = CONF_OPER_CHWIDTH_320MHZ;
break;
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
default:
- chwidth = CHANWIDTH_USE_HT;
+ chwidth = CONF_OPER_CHWIDTH_USE_HT;
break;
}
@@ -979,10 +985,10 @@
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
if (hapd->iconf->ieee80211ac) {
hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
- if (chwidth == CHANWIDTH_160MHZ)
+ if (chwidth == CONF_OPER_CHWIDTH_160MHZ)
hapd->iconf->vht_capab |=
VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
- else if (chwidth == CHANWIDTH_80P80MHZ)
+ else if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
hapd->iconf->vht_capab |=
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
}
@@ -1145,7 +1151,7 @@
/* set defaults for backwards compatibility */
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
- hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
+ hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_USE_HT);
if (acs_res->ch_width == 40) {
if (is_6ghz_freq(acs_res->pri_freq))
hostapd_set_oper_centr_freq_seg0_idx(
@@ -1155,22 +1161,33 @@
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf, acs_res->vht_seg0_center_ch);
if (acs_res->vht_seg1_center_ch == 0) {
- hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_80MHZ);
+ hostapd_set_oper_chwidth(
+ hapd->iconf, CONF_OPER_CHWIDTH_80MHZ);
} else {
- hostapd_set_oper_chwidth(hapd->iconf,
- CHANWIDTH_80P80MHZ);
+ hostapd_set_oper_chwidth(
+ hapd->iconf,
+ CONF_OPER_CHWIDTH_80P80MHZ);
hostapd_set_oper_centr_freq_seg1_idx(
hapd->iconf,
acs_res->vht_seg1_center_ch);
}
} else if (acs_res->ch_width == 160) {
- hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_chwidth(hapd->iconf,
+ CONF_OPER_CHWIDTH_160MHZ);
hostapd_set_oper_centr_freq_seg0_idx(
hapd->iconf, acs_res->vht_seg1_center_ch);
}
}
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iface->conf->ieee80211be && acs_res->ch_width == 320) {
+ hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_320MHZ);
+ hostapd_set_oper_centr_freq_seg0_idx(
+ hapd->iconf, acs_res->vht_seg1_center_ch);
+ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
out:
ret = hostapd_acs_completed(hapd->iface, err);
if (ret) {
@@ -1543,7 +1560,8 @@
static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
- const u8 *data, size_t data_len)
+ const u8 *data, size_t data_len,
+ enum frame_encryption encrypted)
{
struct hostapd_iface *iface = hapd->iface;
struct sta_info *sta;
@@ -1557,7 +1575,7 @@
}
}
- ieee802_1x_receive(hapd, src, data, data_len);
+ ieee802_1x_receive(hapd, src, data, data_len, encrypted);
}
#endif /* HOSTAPD */
@@ -1952,7 +1970,8 @@
case EVENT_EAPOL_RX:
hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
data->eapol_rx.data,
- data->eapol_rx.data_len);
+ data->eapol_rx.data_len,
+ data->eapol_rx.encrypted);
break;
case EVENT_ASSOC:
if (!data)
diff --git a/src/ap/gas_query_ap.c b/src/ap/gas_query_ap.c
index fdb3cad..3d94407 100644
--- a/src/ap/gas_query_ap.c
+++ b/src/ap/gas_query_ap.c
@@ -29,6 +29,8 @@
#define GAS_QUERY_WAIT_TIME_INITIAL 1000
#define GAS_QUERY_WAIT_TIME_COMEBACK 150
+#define GAS_QUERY_MAX_COMEBACK_DELAY 60000
+
/**
* struct gas_query_pending - Pending GAS query
*/
@@ -545,6 +547,8 @@
if (pos + 2 > data + len)
return 0;
comeback_delay = WPA_GET_LE16(pos);
+ if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
+ comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
pos += 2;
/* Advertisement Protocol element */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ef53c41..3681df6 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1238,7 +1238,8 @@
* Short SSID calculation is identical to FCS and it is defined in
* IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID).
*/
- conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+ conf->ssid.short_ssid = ieee80211_crc32(conf->ssid.ssid,
+ conf->ssid.ssid_len);
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR
@@ -1718,7 +1719,7 @@
goto fail;
if (iface->conf->op_class) {
- int ch_width;
+ enum oper_chan_width ch_width;
ch_width = op_class_to_ch_width(iface->conf->op_class);
hostapd_set_oper_chwidth(iface->conf, ch_width);
@@ -1784,6 +1785,16 @@
}
+static int fst_hostapd_get_hw_modes_cb(void *ctx,
+ struct hostapd_hw_modes **modes)
+{
+ struct hostapd_data *hapd = ctx;
+
+ *modes = hapd->iface->hw_features;
+ return hapd->iface->num_hw_features;
+}
+
+
static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
{
struct hostapd_data *hapd = ctx;
@@ -1876,9 +1887,11 @@
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
struct fst_wpa_obj *iface_obj)
{
+ os_memset(iface_obj, 0, sizeof(*iface_obj));
iface_obj->ctx = hapd;
iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
+ iface_obj->get_hw_modes = fst_hostapd_get_hw_modes_cb;
iface_obj->set_ies = fst_hostapd_set_ies_cb;
iface_obj->send_action = fst_hostapd_send_action_cb;
iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
@@ -3491,16 +3504,21 @@
case 0:
case 20:
case 40:
- hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+ hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT);
break;
case 80:
if (params->center_freq2)
- hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ);
+ hostapd_set_oper_chwidth(conf,
+ CONF_OPER_CHWIDTH_80P80MHZ);
else
- hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
+ hostapd_set_oper_chwidth(conf,
+ CONF_OPER_CHWIDTH_80MHZ);
break;
case 160:
- hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ);
+ break;
+ case 320:
+ hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_320MHZ);
break;
default:
return -1;
@@ -3538,15 +3556,15 @@
switch (settings->freq_params.bandwidth) {
case 80:
if (settings->freq_params.center_freq2)
- bandwidth = CHANWIDTH_80P80MHZ;
+ bandwidth = CONF_OPER_CHWIDTH_80P80MHZ;
else
- bandwidth = CHANWIDTH_80MHZ;
+ bandwidth = CONF_OPER_CHWIDTH_80MHZ;
break;
case 160:
- bandwidth = CHANWIDTH_160MHZ;
+ bandwidth = CONF_OPER_CHWIDTH_160MHZ;
break;
default:
- bandwidth = CHANWIDTH_USE_HT;
+ bandwidth = CONF_OPER_CHWIDTH_USE_HT;
break;
}
@@ -3676,7 +3694,8 @@
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
- int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT;
+ int seg0_idx = 0, seg1_idx = 0;
+ enum oper_chan_width bw = CONF_OPER_CHWIDTH_USE_HT;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
@@ -3689,16 +3708,19 @@
case 0:
case 20:
case 40:
- bw = CHANWIDTH_USE_HT;
+ bw = CONF_OPER_CHWIDTH_USE_HT;
break;
case 80:
if (freq_params->center_freq2)
- bw = CHANWIDTH_80P80MHZ;
+ bw = CONF_OPER_CHWIDTH_80P80MHZ;
else
- bw = CHANWIDTH_80MHZ;
+ bw = CONF_OPER_CHWIDTH_80MHZ;
break;
case 160:
- bw = CHANWIDTH_160MHZ;
+ bw = CONF_OPER_CHWIDTH_160MHZ;
+ break;
+ case 320:
+ bw = CONF_OPER_CHWIDTH_320MHZ;
break;
default:
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
@@ -3792,7 +3814,7 @@
r = os_random() % HE_OPERATION_BSS_COLOR_MAX;
for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) {
- if (r && !(hapd->color_collision_bitmap & BIT(r)))
+ if (r && !(hapd->color_collision_bitmap & (1ULL << r)))
break;
r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 6b9b65f..e121362 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -76,6 +76,17 @@
#ifdef CONFIG_DPP
struct dpp_global *dpp;
+#ifdef CONFIG_DPP3
+ struct os_reltime dpp_pb_time;
+ struct os_reltime dpp_pb_announce_time;
+ struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT];
+ struct dpp_bootstrap_info *dpp_pb_bi;
+ u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN];
+ u8 dpp_pb_resp_hash[SHA256_MAC_LEN];
+ struct os_reltime dpp_pb_last_resp;
+ bool dpp_pb_result_indicated;
+ char *dpp_pb_cmd;
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
#ifdef CONFIG_CTRL_IFACE_UDP
@@ -324,6 +335,7 @@
#ifdef CONFIG_PROXYARP
struct l2_packet_data *sock_dhcp;
struct l2_packet_data *sock_ndisc;
+ bool x_snoop_initialized;
#endif /* CONFIG_PROXYARP */
#ifdef CONFIG_MESH
int num_plinks;
@@ -400,6 +412,7 @@
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
+ size_t dpp_pkex_code_len;
char *dpp_pkex_identifier;
enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
@@ -420,6 +433,7 @@
int dpp_chirp_round;
int dpp_chirp_scan_done;
int dpp_chirp_listen;
+ struct os_reltime dpp_relay_last_needs_ctrl;
#endif /* CONFIG_DPP2 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 4b66b02..ed5ff41 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -371,7 +371,7 @@
iface->conf->secondary_channel = 0;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0);
- hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT);
+ hostapd_set_oper_chwidth(iface->conf, CONF_OPER_CHWIDTH_USE_HT);
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -1087,13 +1087,14 @@
if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G ||
iface->conf->ieee80211n || iface->conf->ieee80211ac ||
- iface->conf->ieee80211ax) &&
+ iface->conf->ieee80211ax || iface->conf->ieee80211be) &&
iface->conf->channel == 14) {
- wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14");
+ wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14");
iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
iface->conf->ieee80211n = 0;
iface->conf->ieee80211ac = 0;
iface->conf->ieee80211ax = 0;
+ iface->conf->ieee80211be = 0;
}
iface->current_mode = NULL;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 394e292..a65a296 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -982,7 +982,8 @@
sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar;
sta->sae->peer_commit_scalar = NULL;
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- sta->sae->pmk, sta->sae->pmkid);
+ sta->sae->pmk, sta->sae->pmk_len,
+ sta->sae->pmkid, sta->sae->akmp);
sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
}
@@ -1233,6 +1234,10 @@
if (sae_pwe == 0 && sae_pk)
sae_pwe = 2;
#endif /* CONFIG_SAE_PK */
+ if (sae_pwe == 0 &&
+ (hapd->conf->wpa_key_mgmt &
+ (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY)))
+ sae_pwe = 2;
return ((sae_pwe == 0 || sae_pwe == 3) &&
status_code == WLAN_STATUS_SUCCESS) ||
@@ -2514,7 +2519,8 @@
* restrict this only for PASN.
*/
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- pasn->sae.pmk, pasn->sae.pmkid);
+ pasn->sae.pmk, pasn->sae.pmk_len,
+ pasn->sae.pmkid, pasn->sae.akmp);
return 0;
}
@@ -2661,6 +2667,15 @@
goto fail;
}
+ if (pasn->secure_ltf) {
+ ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Failed to derive LTF keyseed");
+ goto fail;
+ }
+ }
+
wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
wpabuf_free(pasn->secret);
@@ -2842,6 +2857,38 @@
}
+static int pasn_set_keys_from_cache(struct hostapd_data *hapd,
+ const u8 *own_addr, const u8 *sta_addr,
+ int cipher, int akmp)
+{
+ struct ptksa_cache_entry *entry;
+
+ entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher);
+ if (!entry) {
+ wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
+ " not present in PTKSA cache", MAC2STR(sta_addr));
+ return -1;
+ }
+
+ if (os_memcmp(entry->own_addr, own_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: own addr " MACSTR " and PTKSA entry own addr "
+ MACSTR " differ",
+ MAC2STR(own_addr), MAC2STR(entry->own_addr));
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
+ MAC2STR(sta_addr));
+ hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher,
+ entry->ptk.tk_len, entry->ptk.tk,
+ entry->ptk.ltf_keyseed_len,
+ entry->ptk.ltf_keyseed, 0);
+
+ return 0;
+}
+
+
static int
pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *cached_pmk, size_t cached_pmk_len,
@@ -2898,6 +2945,16 @@
return -1;
}
+ if (sta->pasn->secure_ltf) {
+ ret = wpa_ltf_keyseed(&sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to derive LTF keyseed");
+ return -1;
+ }
+ }
+
wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
return 0;
}
@@ -3161,7 +3218,7 @@
sta->pasn->akmp = rsn_data.key_mgmt;
sta->pasn->cipher = rsn_data.pairwise_cipher;
- derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
+ derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP) &&
ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
WLAN_RSNX_CAPAB_SECURE_LTF);
#ifdef CONFIG_TESTING_OPTIONS
@@ -3174,6 +3231,13 @@
sta->pasn->kdk_len = 0;
wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len);
+ if ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP) &&
+ ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SECURE_LTF))
+ sta->pasn->secure_ltf = true;
+ else
+ sta->pasn->secure_ltf = false;
+
if (!elems.pasn_params || !elems.pasn_params_len) {
wpa_printf(MSG_DEBUG,
"PASN: No PASN Parameters element found");
@@ -3496,8 +3560,10 @@
wpa_printf(MSG_INFO,
"PASN: Success handling transaction == 3. Store PTK");
- ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
- &sta->pasn->ptk);
+ ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr,
+ sta->pasn->cipher, 43200, &sta->pasn->ptk, NULL, NULL);
+ pasn_set_keys_from_cache(hapd, hapd->own_addr, sta->addr,
+ sta->pasn->cipher, sta->pasn->akmp);
fail:
ap_free_sta(hapd, sta);
}
@@ -4629,6 +4695,9 @@
if (hapd->conf->wpa && wpa_ie) {
enum wpa_validate_result res;
+ if (check_sa_query(hapd, sta, reassoc))
+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
wpa_ie -= 2;
wpa_ie_len += 2;
if (sta->wpa_sm == NULL)
@@ -4652,9 +4721,6 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- if (check_sa_query(hapd, sta, reassoc))
- return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
-
if (wpa_auth_uses_mfp(sta->wpa_sm))
sta->flags |= WLAN_STA_MFP;
else
@@ -4686,7 +4752,7 @@
sta->auth_alg == WLAN_AUTH_OPEN) {
struct rsn_pmksa_cache_entry *sa;
sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
- if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
+ if (!sa || !wpa_key_mgmt_sae(sa->akmp)) {
wpa_printf(MSG_DEBUG,
"SAE: No PMKSA cache entry found for "
MACSTR, MAC2STR(sta->addr));
@@ -6589,7 +6655,8 @@
ieee802_1x_receive(
hapd, mgmt->da,
wpabuf_head(sta->pending_eapol_rx->buf),
- wpabuf_len(sta->pending_eapol_rx->buf));
+ wpabuf_len(sta->pending_eapol_rx->buf),
+ sta->pending_eapol_rx->encrypted);
}
wpabuf_free(sta->pending_eapol_rx->buf);
os_free(sta->pending_eapol_rx);
@@ -7032,7 +7099,7 @@
#endif /* CONFIG_IEEE80211AX */
switch (hostapd_get_oper_chwidth(iconf)) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
/* Max Transmit Power count = 0 (20 MHz) */
tx_pwr_count = 0;
@@ -7041,12 +7108,12 @@
tx_pwr_count = 1;
}
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
tx_pwr_count = 2;
break;
- case CHANWIDTH_80P80MHZ:
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
tx_pwr_count = 3;
break;
@@ -7449,7 +7516,7 @@
break;
*eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
- os_memcpy(eid, bss->conf->bssid, ETH_ALEN);
+ os_memcpy(eid, bss->own_addr, ETH_ALEN);
eid += ETH_ALEN;
os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
eid += 4;
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index dbbf9a6..ec36a9e 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -41,25 +41,41 @@
}
-static u8 ieee80211_eht_mcs_set_size(const u8 *he_phy_cap,
+static u8 ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode, u8 opclass,
+ const u8 *he_phy_cap,
const u8 *eht_phy_cap)
{
u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+ bool band24, band5, band6;
- if ((he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
- (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
- HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
- HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
- HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
+ band24 = mode == HOSTAPD_MODE_IEEE80211B ||
+ mode == HOSTAPD_MODE_IEEE80211G ||
+ mode == NUM_HOSTAPD_MODES;
+ band5 = mode == HOSTAPD_MODE_IEEE80211A ||
+ mode == NUM_HOSTAPD_MODES;
+ band6 = is_6ghz_op_class(opclass);
+
+ if (band24 &&
+ (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0)
return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
- if (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
- (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
- HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))
- sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+ if (band5 &&
+ (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
+ return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
- if (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
- EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+ if (band5 &&
+ (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)))
+ sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ if (band6 &&
+ (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK))
sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
return sz;
@@ -81,7 +97,8 @@
if (!eht_cap->eht_supported)
return 0;
- len += ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ len += ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class,
+ mode->he_capab[opmode].phy_cap,
eht_cap->phy_cap);
len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]),
eht_cap->phy_cap);
@@ -133,7 +150,9 @@
pos = cap->optional;
- mcs_nss_len = ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ mcs_nss_len = ieee80211_eht_mcs_set_size(mode->mode,
+ hapd->iconf->op_class,
+ mode->he_capab[opmode].phy_cap,
eht_cap->phy_cap);
if (mcs_nss_len) {
os_memcpy(pos, eht_cap->mcs, mcs_nss_len);
@@ -157,7 +176,8 @@
{
struct hostapd_config *conf = hapd->iconf;
struct ieee80211_eht_operation *oper;
- u8 *pos = eid, chwidth, seg0 = 0, seg1 = 0;
+ u8 *pos = eid, seg0 = 0, seg1 = 0;
+ enum oper_chan_width chwidth;
if (!hapd->iface->current_mode)
return eid;
@@ -177,9 +197,7 @@
seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
switch (chwidth) {
-#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal
- * needs to be able to define this. */
- case CHANWIDTH_320MHZ:
+ case CONF_OPER_CHWIDTH_320MHZ:
oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ;
seg1 = seg0;
if (hapd->iconf->channel < seg0)
@@ -187,8 +205,7 @@
else
seg0 += 16;
break;
-#endif
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ;
seg1 = seg0;
if (hapd->iconf->channel < seg0)
@@ -196,10 +213,10 @@
else
seg0 += 8;
break;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ;
break;
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (seg0)
oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ;
break;
@@ -257,7 +274,8 @@
capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab;
sta_mcs = capab->optional;
- if (ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ if (ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class,
+ mode->he_capab[opmode].phy_cap,
mode->eht_capab[opmode].phy_cap) ==
EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY)
return check_valid_eht_mcs_nss(
@@ -265,10 +283,14 @@
EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY);
switch (hapd->iface->conf->eht_oper_chwidth) {
- /* TODO: CHANWIDTH_320MHZ */
- case CHANWIDTH_80P80MHZ:
- case CHANWIDTH_160MHZ:
- mcs_count = 2;
+ case CONF_OPER_CHWIDTH_320MHZ:
+ mcs_count++;
+ /* fall through */
+ case CONF_OPER_CHWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
+ mcs_count++;
+ break;
+ default:
break;
}
@@ -277,7 +299,9 @@
}
-static bool ieee80211_invalid_eht_cap_size(const u8 *he_cap, const u8 *eht_cap,
+static bool ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode,
+ u8 opclass,
+ const u8 *he_cap, const u8 *eht_cap,
size_t len)
{
const struct ieee80211_he_capabilities *he_capab;
@@ -293,7 +317,8 @@
if (len < cap_len)
return true;
- cap_len += ieee80211_eht_mcs_set_size(he_phy_cap, cap->phy_cap);
+ cap_len += ieee80211_eht_mcs_set_size(mode, opclass, he_phy_cap,
+ cap->phy_cap);
if (len < cap_len)
return true;
@@ -310,10 +335,14 @@
const u8 *he_capab, size_t he_capab_len,
const u8 *eht_capab, size_t eht_capab_len)
{
+ struct hostapd_hw_modes *c_mode = hapd->iface->current_mode;
+ enum hostapd_hw_mode mode = c_mode ? c_mode->mode : NUM_HOSTAPD_MODES;
+
if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be ||
!he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN ||
!eht_capab ||
- ieee80211_invalid_eht_cap_size(he_capab, eht_capab,
+ ieee80211_invalid_eht_cap_size(mode, hapd->iconf->op_class,
+ he_capab, eht_capab,
eht_capab_len) ||
!check_valid_eht_mcs(hapd, eht_capab, opmode)) {
sta->flags &= ~WLAN_STA_EHT;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 1e74c58..12273c3 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -102,20 +102,22 @@
mode->he_capab[opmode].phy_cap);
switch (hapd->iface->conf->he_oper_chwidth) {
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
he_oper_chwidth |=
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
mcs_nss_size += 4;
/* fall through */
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
mcs_nss_size += 4;
/* fall through */
- case CHANWIDTH_80MHZ:
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_USE_HT:
he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
break;
+ default:
+ break;
}
ie_size += mcs_nss_size + ppet_size;
@@ -217,7 +219,7 @@
pos += 6; /* skip the fixed part */
if (is_6ghz_op_class(hapd->iconf->op_class)) {
- u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+ u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
u8 control;
@@ -430,10 +432,10 @@
* band/stream cases.
*/
switch (hapd->iface->conf->he_oper_chwidth) {
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
mcs_count = 3;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
mcs_count = 2;
break;
default:
@@ -531,7 +533,8 @@
u8 *mac_cap;
if (!hapd->iface->current_mode ||
- !hapd->iface->current_mode->he_capab[mode].he_supported)
+ !hapd->iface->current_mode->he_capab[mode].he_supported ||
+ !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
return 0;
mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 6154895..eaeaec5 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -17,6 +17,7 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "wpa_auth.h"
+#include "dpp_hostapd.h"
#include "ieee802_11.h"
@@ -412,8 +413,7 @@
*pos |= 0x01;
#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax &&
- hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
+ if (hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP))
*pos |= 0x40; /* Bit 78 - TWT responder */
#endif /* CONFIG_IEEE80211AX */
break;
@@ -873,7 +873,7 @@
size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd)
{
#ifdef CONFIG_DPP2
- if (hapd->conf->dpp_configurator_connectivity)
+ if (hostapd_dpp_configurator_connectivity(hapd))
return 6;
#endif /* CONFIG_DPP2 */
return 0;
@@ -885,7 +885,7 @@
u8 *pos = eid;
#ifdef CONFIG_DPP2
- if (!hapd->conf->dpp_configurator_connectivity || len < 6)
+ if (!hostapd_dpp_configurator_connectivity(hapd) || len < 6)
return pos;
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
@@ -998,7 +998,7 @@
* If a VHT Operation element was present, use it to determine
* the supported channel bandwidth.
*/
- if (oper->vht_op_info_chwidth == 0) {
+ if (oper->vht_op_info_chwidth == CHANWIDTH_USE_HT) {
requested_bw = ht_40mhz ? 40 : 20;
} else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
requested_bw = 80;
@@ -1063,7 +1063,8 @@
if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
(hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
- hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
+ hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk ||
+ wpa_key_mgmt_sae_ext_key(hapd->conf->wpa_key_mgmt)) &&
hapd->conf->sae_pwe != 3) {
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
@@ -1072,11 +1073,11 @@
#endif /* CONFIG_SAE_PK */
}
- if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
- if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
- if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP)
capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
flen = (capab & 0xff00) ? 2 : 1;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 828f0ab..681b6d7 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -96,12 +96,12 @@
hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
- if (hapd->iconf->vht_oper_chwidth == 2) {
+ if (hapd->iconf->vht_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
/*
* Convert 160 MHz channel width to new style as interop
* workaround.
*/
- oper->vht_op_info_chwidth = 1;
+ oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
oper->vht_op_info_chan_center_freq_seg1_idx =
oper->vht_op_info_chan_center_freq_seg0_idx;
if (hapd->iconf->channel <
@@ -109,12 +109,13 @@
oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
else
oper->vht_op_info_chan_center_freq_seg0_idx += 8;
- } else if (hapd->iconf->vht_oper_chwidth == 3) {
+ } else if (hapd->iconf->vht_oper_chwidth ==
+ CONF_OPER_CHWIDTH_80P80MHZ) {
/*
* Convert 80+80 MHz channel width to new style as interop
* workaround.
*/
- oper->vht_op_info_chwidth = 1;
+ oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
}
/* VHT Basic MCS set comes from hw */
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index fb5e920..d90792c 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -998,7 +998,7 @@
static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
- size_t len)
+ size_t len, enum frame_encryption encrypted)
{
if (sta->pending_eapol_rx) {
wpabuf_free(sta->pending_eapol_rx->buf);
@@ -1016,21 +1016,39 @@
return;
}
+ sta->pending_eapol_rx->encrypted = encrypted;
os_get_reltime(&sta->pending_eapol_rx->rx_time);
}
+static bool ieee802_1x_check_encryption(struct sta_info *sta,
+ enum frame_encryption encrypted,
+ u8 type)
+{
+ if (encrypted != FRAME_NOT_ENCRYPTED)
+ return true;
+ if (type != IEEE802_1X_TYPE_EAP_PACKET &&
+ type != IEEE802_1X_TYPE_EAPOL_START &&
+ type != IEEE802_1X_TYPE_EAPOL_LOGOFF)
+ return true;
+ if (!(sta->flags & WLAN_STA_MFP))
+ return true;
+ return !wpa_auth_pairwise_set(sta->wpa_sm);
+}
+
+
/**
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
* @hapd: hostapd BSS data
* @sa: Source address (sender of the EAPOL frame)
* @buf: EAPOL frame
* @len: Length of buf in octets
+ * @encrypted: Whether the frame was encrypted
*
* This function is called for each incoming EAPOL frame from the interface
*/
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
- size_t len)
+ size_t len, enum frame_encryption encrypted)
{
struct sta_info *sta;
struct ieee802_1x_hdr *hdr;
@@ -1043,8 +1061,9 @@
!hapd->conf->wps_state)
return;
- wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
- (unsigned long) len, MAC2STR(sa));
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR
+ " (encrypted=%d)",
+ (unsigned long) len, MAC2STR(sa), encrypted);
sta = ap_get_sta(hapd, sa);
if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
@@ -1054,7 +1073,7 @@
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
" for later use", MAC2STR(sta->addr));
- ieee802_1x_save_eapol(sta, buf, len);
+ ieee802_1x_save_eapol(sta, buf, len, encrypted);
}
return;
@@ -1114,6 +1133,12 @@
return;
}
+ if (!ieee802_1x_check_encryption(sta, encrypted, hdr->type)) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.1X: Discard unencrypted EAPOL message - encryption was expected");
+ return;
+ }
+
if (!sta->eapol_sm) {
sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
if (!sta->eapol_sm)
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 70dc11a..1469351 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -19,7 +19,7 @@
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
- size_t len);
+ size_t len, enum frame_encryption encrypted);
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index e37324f..5b276e8 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -136,7 +136,7 @@
os_memcpy(entry->bssid, bssid, ETH_ALEN);
os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
- entry->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
+ entry->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
entry->nr = wpabuf_dup(nr);
if (!entry->nr)
@@ -199,19 +199,21 @@
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
int ht, int vht, int he)
{
- u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
+ enum oper_chan_width oper_chwidth;
+
+ oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
if (!ht && !vht && !he)
return NR_CHAN_WIDTH_20;
if (!hapd->iconf->secondary_channel)
return NR_CHAN_WIDTH_20;
- if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT)
+ if ((!vht && !he) || oper_chwidth == CONF_OPER_CHWIDTH_USE_HT)
return NR_CHAN_WIDTH_40;
- if (oper_chwidth == CHANWIDTH_80MHZ)
+ if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
return NR_CHAN_WIDTH_80;
- if (oper_chwidth == CHANWIDTH_160MHZ)
+ if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ)
return NR_CHAN_WIDTH_160;
- if (oper_chwidth == CHANWIDTH_80P80MHZ)
+ if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
return NR_CHAN_WIDTH_80P80;
return NR_CHAN_WIDTH_20;
}
diff --git a/src/ap/preauth_auth.c b/src/ap/preauth_auth.c
index 2ff1861..3284a10 100644
--- a/src/ap/preauth_auth.c
+++ b/src/ap/preauth_auth.c
@@ -90,7 +90,7 @@
return;
sta->preauth_iface = piface;
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
- len - sizeof(*ethhdr));
+ len - sizeof(*ethhdr), FRAME_ENCRYPTION_UNKNOWN);
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index af8f171..d2a8344 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -65,6 +65,7 @@
struct pending_eapol_rx {
struct wpabuf *buf;
struct os_reltime rx_time;
+ enum frame_encryption encrypted;
};
enum pasn_fils_state {
@@ -87,6 +88,7 @@
int akmp;
int cipher;
u16 group;
+ bool secure_ltf;
u8 trans_seq;
u8 wrapped_data_format;
size_t kdk_len;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index ad91883..64a1800 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -149,6 +149,20 @@
}
+#ifdef CONFIG_PASN
+static inline int wpa_auth_set_ltf_keyseed(struct wpa_authenticator *wpa_auth,
+ const u8 *peer_addr,
+ const u8 *ltf_keyseed,
+ size_t ltf_keyseed_len)
+{
+ if (!wpa_auth->cb->set_ltf_keyseed)
+ return -1;
+ return wpa_auth->cb->set_ltf_keyseed(wpa_auth->cb_ctx, peer_addr,
+ ltf_keyseed, ltf_keyseed_len);
+}
+#endif /* CONFIG_PASN */
+
+
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
@@ -735,16 +749,13 @@
{
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr)) {
- u32 start;
wpa_printf(MSG_DEBUG,
"P2P: Free assigned IP address %u.%u.%u.%u from "
- MACSTR,
+ MACSTR " (bit %u)",
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
- MAC2STR(sm->addr));
- start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
- bitfield_clear(sm->wpa_auth->ip_pool,
- WPA_GET_BE32(sm->ip_addr) - start);
+ MAC2STR(sm->addr), sm->ip_addr_bit);
+ bitfield_clear(sm->wpa_auth->ip_pool, sm->ip_addr_bit);
}
#endif /* CONFIG_P2P */
if (sm->GUpdateStationKeys) {
@@ -2204,6 +2215,7 @@
{
u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
size_t pmkid_len = 0;
+ u16 key_info;
SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
sm->PTKRequest = false;
@@ -2307,8 +2319,10 @@
}
if (!pmkid)
pmkid_len = 0;
- wpa_send_eapol(sm->wpa_auth, sm,
- WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+ key_info = WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE;
+ if (sm->pairwise_set && sm->wpa != WPA_VERSION_WPA)
+ key_info |= WPA_KEY_INFO_SECURE;
+ wpa_send_eapol(sm->wpa_auth, sm, key_info, NULL,
sm->ANonce, pmkid, pmkid_len, 0, 0);
}
@@ -2320,6 +2334,7 @@
const u8 *z = NULL;
size_t z_len = 0, kdk_len;
int akmp;
+ int ret;
if (sm->wpa_auth->conf.force_kdk_derivation ||
(sm->wpa_auth->conf.secure_ltf &&
@@ -2333,16 +2348,33 @@
if (sm->ft_completed) {
u8 ptk_name[WPA_PMK_NAME_LEN];
- return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
- sm->SNonce, sm->ANonce,
- sm->addr, sm->wpa_auth->addr,
- sm->pmk_r1_name,
- ptk, ptk_name,
- sm->wpa_key_mgmt,
- sm->pairwise,
- kdk_len);
+ ret = wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
+ sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr,
+ sm->pmk_r1_name, ptk,
+ ptk_name, sm->wpa_key_mgmt,
+ sm->pairwise, kdk_len);
+ } else {
+ ret = wpa_auth_derive_ptk_ft(sm, ptk);
}
- return wpa_auth_derive_ptk_ft(sm, ptk);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "FT: PTK derivation failed");
+ return ret;
+ }
+
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe,
+ WLAN_RSNX_CAPAB_SECURE_LTF)) {
+ ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt,
+ sm->pairwise);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "FT: LTF keyseed derivation failed");
+ }
+ }
+#endif /* CONFIG_PASN */
+ return ret;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -2356,9 +2388,27 @@
akmp = sm->wpa_key_mgmt;
if (force_sha256)
akmp |= WPA_KEY_MGMT_PSK_SHA256;
- return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
- sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, akmp, sm->pairwise, z, z_len, kdk_len);
+ ret = wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
+ sm->wpa_auth->addr, sm->addr, sm->ANonce,
+ snonce, ptk, akmp, sm->pairwise, z, z_len,
+ kdk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: PTK derivation failed");
+ return ret;
+ }
+
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
+ ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, sm->pairwise);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: LTF keyseed derivation failed");
+ }
+ }
+#endif /* CONFIG_PASN */
+ return ret;
}
@@ -2389,6 +2439,19 @@
fils_ft, &fils_ft_len, kdk_len);
if (res < 0)
return res;
+
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
+ res = wpa_ltf_keyseed(&sm->PTK, sm->wpa_key_mgmt, sm->pairwise);
+ if (res) {
+ wpa_printf(MSG_ERROR,
+ "FILS: LTF keyseed derivation failed");
+ return res;
+ }
+ }
+#endif /* CONFIG_PASN */
+
sm->PTK_valid = true;
sm->tk_already_set = false;
@@ -2892,6 +2955,20 @@
wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
return -1;
}
+
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
+ sm->PTK.ltf_keyseed,
+ sm->PTK.ltf_keyseed_len)) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to set LTF keyseed to driver");
+ return -1;
+ }
+#endif /* CONFIG_PASN */
+
+ sm->pairwise_set = true;
sm->tk_already_set = true;
wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
@@ -3178,12 +3255,14 @@
if (idx >= 0) {
u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start);
bitfield_set(wpa_auth->ip_pool, idx);
+ sm->ip_addr_bit = idx;
WPA_PUT_BE32(sm->ip_addr, start + idx);
wpa_printf(MSG_DEBUG,
"P2P: Assigned IP address %u.%u.%u.%u to "
- MACSTR, sm->ip_addr[0], sm->ip_addr[1],
+ MACSTR " (bit %u)",
+ sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
- MAC2STR(sm->addr));
+ MAC2STR(sm->addr), sm->ip_addr_bit);
}
}
#endif /* CONFIG_P2P */
@@ -3487,6 +3566,21 @@
return;
}
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe,
+ WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
+ sm->PTK.ltf_keyseed,
+ sm->PTK.ltf_keyseed_len)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to set LTF keyseed to driver");
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+#endif /* CONFIG_PASN */
+
/* WPA2 send GTK in the 4-way handshake */
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
@@ -3698,6 +3792,22 @@
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe,
+ WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
+ sm->PTK.ltf_keyseed,
+ sm->PTK.ltf_keyseed_len)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: Failed to set LTF keyseed to driver");
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+#endif /* CONFIG_PASN */
+
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = true;
@@ -4866,16 +4976,17 @@
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
- const u8 *pmk, const u8 *pmkid)
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ int akmp)
{
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
- wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
- if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
- NULL, 0,
- wpa_auth->addr, addr, 0, NULL,
- WPA_KEY_MGMT_SAE))
+ wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, pmk_len);
+ if (!akmp)
+ akmp = WPA_KEY_MGMT_SAE;
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
+ NULL, 0, wpa_auth->addr, addr, 0, NULL, akmp))
return 0;
return -1;
@@ -4953,13 +5064,14 @@
struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
+ size_t pmk_len, int akmp,
const u8 *pmkid, int expiration)
{
struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
- entry = pmksa_cache_auth_create_entry(pmk, PMK_LEN, pmkid, NULL, 0, aa,
- spa, 0, NULL, WPA_KEY_MGMT_SAE);
+ entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, NULL, 0, aa,
+ spa, 0, NULL, akmp);
if (!entry)
return NULL;
@@ -5273,7 +5385,8 @@
{
if (!sm)
return 0;
- return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
+ return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY;
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 348a1de..a18f7cb 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -352,6 +352,10 @@
#ifdef CONFIG_MESH
int (*start_ampe)(void *ctx, const u8 *sta_addr);
#endif /* CONFIG_MESH */
+#ifdef CONFIG_PASN
+ int (*set_ltf_keyseed)(void *ctx, const u8 *addr, const u8 *ltf_keyseed,
+ size_t ltf_keyseed_len);
+#endif /* CONFIG_PASN */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
@@ -427,7 +431,8 @@
int session_timeout,
struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
- const u8 *pmk, const u8 *pmkid);
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ int akmp);
void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
@@ -441,6 +446,7 @@
char *buf, size_t len);
struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
+ size_t pmk_len, int akmp,
const u8 *pmkid, int expiration);
int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
struct rsn_pmksa_cache_entry *entry);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 7a97613..1b1324b 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2805,6 +2805,20 @@
}
+#ifdef CONFIG_PASN
+static inline int wpa_auth_set_ltf_keyseed(struct wpa_authenticator *wpa_auth,
+ const u8 *peer_addr,
+ const u8 *ltf_keyseed,
+ size_t ltf_keyseed_len)
+{
+ if (!wpa_auth->cb->set_ltf_keyseed)
+ return -1;
+ return wpa_auth->cb->set_ltf_keyseed(wpa_auth->cb_ctx, peer_addr,
+ ltf_keyseed, ltf_keyseed_len);
+}
+#endif /* CONFIG_PASN */
+
+
static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
@@ -2849,6 +2863,18 @@
sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
return;
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr,
+ sm->PTK.ltf_keyseed,
+ sm->PTK.ltf_keyseed_len)) {
+ wpa_printf(MSG_ERROR,
+ "FT: Failed to set LTF keyseed to driver");
+ return;
+ }
+#endif /* CONFIG_PASN */
+
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = true;
sm->tk_already_set = true;
@@ -3210,6 +3236,15 @@
pairwise, kdk_len) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_PASN
+ if (sm->wpa_auth->conf.secure_ltf &&
+ ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_ltf_keyseed(&sm->PTK, sm->wpa_key_mgmt, pairwise)) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to derive LTF keyseed");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_PASN */
+
sm->pairwise = pairwise;
sm->PTK_valid = true;
sm->tk_already_set = false;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9e8dae1..a510952 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -350,6 +350,8 @@
if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
if (!sta->sae || prev_psk)
return NULL;
+ if (psk_len)
+ *psk_len = sta->sae->pmk_len;
return sta->sae->pmk;
}
if (sta && wpa_auth_uses_sae(sta->wpa_sm)) {
@@ -934,7 +936,8 @@
{
struct hostapd_data *hapd = ctx;
- ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk);
+ ptksa_cache_add(hapd->ptksa, hapd->own_addr, addr, cipher, life_time,
+ ptk, NULL, NULL);
}
@@ -1469,6 +1472,21 @@
#endif /* CONFIG_NO_RADIUS */
+#ifdef CONFIG_PASN
+static int hostapd_set_ltf_keyseed(void *ctx, const u8 *peer_addr,
+ const u8 *ltf_keyseed,
+ size_t ltf_keyseed_len)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hostapd_drv_set_secure_ranging_ctx(hapd, hapd->own_addr,
+ peer_addr, 0, 0, NULL,
+ ltf_keyseed_len,
+ ltf_keyseed, 0);
+}
+#endif /* CONFIG_PASN */
+
+
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
@@ -1515,6 +1533,9 @@
#ifndef CONFIG_NO_RADIUS
.request_radius_psk = hostapd_request_radius_psk,
#endif /* CONFIG_NO_RADIUS */
+#ifdef CONFIG_PASN
+ .set_ltf_keyseed = hostapd_set_ltf_keyseed,
+#endif /* CONFIG_PASN */
};
const u8 *wpa_ie;
size_t wpa_ie_len;
@@ -1551,11 +1572,12 @@
#endif /* CONFIG_OCV */
_conf.secure_ltf =
- !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF);
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP);
_conf.secure_rtt =
- !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT);
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP);
_conf.prot_range_neg =
- !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
+ !!(hapd->iface->drv_flags2 &
+ WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP);
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 17cb5a2..5bd699c 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -152,6 +152,7 @@
#ifdef CONFIG_P2P
u8 ip_addr[4];
+ unsigned int ip_addr_bit;
#endif /* CONFIG_P2P */
#ifdef CONFIG_FILS
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 524922e..1c8affa 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -228,11 +228,21 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
#endif /* CONFIG_SAE */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
@@ -395,7 +405,8 @@
size_t flen;
if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
- (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk)) {
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk ||
+ wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt))) {
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (conf->sae_pk)
@@ -670,8 +681,12 @@
#ifdef CONFIG_SAE
else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
selector = RSN_AUTH_KEY_MGMT_SAE;
+ else if (data.key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
+ selector = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
+ selector = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
@@ -778,8 +793,12 @@
#ifdef CONFIG_SAE
else if (key_mgmt & WPA_KEY_MGMT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+ else if (key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+ else if (key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
index aef9a53..029f4de 100644
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -31,6 +31,8 @@
return -1;
}
+ hapd->x_snoop_initialized = true;
+
if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
1)) {
wpa_printf(MSG_DEBUG,
@@ -125,7 +127,10 @@
void x_snoop_deinit(struct hostapd_data *hapd)
{
+ if (!hapd->x_snoop_initialized)
+ return;
hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
+ hapd->x_snoop_initialized = false;
}
diff --git a/src/common/defs.h b/src/common/defs.h
index f43bdb5..3e658cb 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -50,12 +50,15 @@
#define WPA_KEY_MGMT_DPP BIT(23)
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
#define WPA_KEY_MGMT_PASN BIT(25)
+#define WPA_KEY_MGMT_SAE_EXT_KEY BIT(26)
+#define WPA_KEY_MGMT_FT_SAE_EXT_KEY BIT(27)
#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
WPA_KEY_MGMT_FT_IEEE8021X | \
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \
WPA_KEY_MGMT_FT_SAE | \
+ WPA_KEY_MGMT_FT_SAE_EXT_KEY | \
WPA_KEY_MGMT_FT_FILS_SHA256 | \
WPA_KEY_MGMT_FT_FILS_SHA384)
@@ -88,7 +91,9 @@
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_SAE |
- WPA_KEY_MGMT_FT_SAE));
+ WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE |
+ WPA_KEY_MGMT_FT_SAE_EXT_KEY));
}
static inline int wpa_key_mgmt_ft(int akm)
@@ -111,7 +116,15 @@
static inline int wpa_key_mgmt_sae(int akm)
{
return !!(akm & (WPA_KEY_MGMT_SAE |
- WPA_KEY_MGMT_FT_SAE));
+ WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE |
+ WPA_KEY_MGMT_FT_SAE_EXT_KEY));
+}
+
+static inline int wpa_key_mgmt_sae_ext_key(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE_EXT_KEY));
}
static inline int wpa_key_mgmt_fils(int akm)
@@ -168,6 +181,13 @@
return akm == WPA_KEY_MGMT_CCKM;
}
+static inline int wpa_key_mgmt_cross_akm(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256 |
+ WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_SAE_EXT_KEY));
+}
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
@@ -429,9 +449,26 @@
CHAN_WIDTH_4320,
CHAN_WIDTH_6480,
CHAN_WIDTH_8640,
+ CHAN_WIDTH_320,
CHAN_WIDTH_UNKNOWN
};
+/* VHT/EDMG/etc. channel widths
+ * Note: The first four values are used in hostapd.conf and as such, must
+ * maintain their defined values. Other values are used internally. */
+enum oper_chan_width {
+ CONF_OPER_CHWIDTH_USE_HT = 0,
+ CONF_OPER_CHWIDTH_80MHZ = 1,
+ CONF_OPER_CHWIDTH_160MHZ = 2,
+ CONF_OPER_CHWIDTH_80P80MHZ = 3,
+ CONF_OPER_CHWIDTH_2160MHZ,
+ CONF_OPER_CHWIDTH_4320MHZ,
+ CONF_OPER_CHWIDTH_6480MHZ,
+ CONF_OPER_CHWIDTH_8640MHZ,
+ CONF_OPER_CHWIDTH_40MHZ_6GHZ,
+ CONF_OPER_CHWIDTH_320MHZ,
+};
+
enum key_flag {
KEY_FLAG_MODIFY = BIT(0),
KEY_FLAG_DEFAULT = BIT(1),
@@ -475,4 +512,12 @@
PTK0_REKEY_ALLOW_NEVER
};
+enum frame_encryption {
+ FRAME_ENCRYPTION_UNKNOWN = -1,
+ FRAME_NOT_ENCRYPTED = 0,
+ FRAME_ENCRYPTED = 1
+};
+
+#define MAX_NUM_MLD_LINKS 15
+
#endif /* DEFS_H */
diff --git a/src/common/dpp.c b/src/common/dpp.c
index cc26b80..559bdcd 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/base64.h"
#include "utils/json.h"
+#include "utils/ip_addr.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/gas.h"
@@ -162,6 +163,7 @@
os_free(info->uri);
os_free(info->info);
os_free(info->chan);
+ os_free(info->host);
os_free(info->pk);
crypto_ec_key_deinit(info->pubkey);
str_clear_free(info->configurator_params);
@@ -369,12 +371,70 @@
}
+static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
+{
+ const char *end;
+ char *port;
+ struct hostapd_ip_addr addr;
+ char buf[100], *pos;
+
+ if (!txt)
+ return 0;
+
+ end = os_strchr(txt, ';');
+ if (!end)
+ end = txt + os_strlen(txt);
+ if (end - txt > (int) sizeof(buf) - 1)
+ return -1;
+ os_memcpy(buf, txt, end - txt);
+ buf[end - txt] = '\0';
+
+ bi->port = DPP_TCP_PORT;
+
+ pos = buf;
+ if (*pos == '[') {
+ pos = &buf[1];
+ port = os_strchr(pos, ']');
+ if (!port)
+ return -1;
+ *port++ = '\0';
+ if (*port == ':')
+ bi->port = atoi(port + 1);
+ }
+
+ if (hostapd_parse_ip_addr(pos, &addr) < 0) {
+ if (buf[0] != '[') {
+ port = os_strrchr(pos, ':');
+ if (port) {
+ *port++ = '\0';
+ bi->port = atoi(port);
+ }
+ }
+ if (hostapd_parse_ip_addr(pos, &addr) < 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Invalid IP address in URI host entry: %s",
+ pos);
+ return -1;
+ }
+ }
+ os_free(bi->host);
+ bi->host = os_memdup(&addr, sizeof(addr));
+ if (!bi->host)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
+ hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
+
+ return 0;
+}
+
+
static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
{
const char *pos = uri;
const char *end;
const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
- const char *version = NULL, *supported_curves = NULL;
+ const char *version = NULL, *supported_curves = NULL, *host = NULL;
struct dpp_bootstrap_info *bi;
wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
@@ -409,6 +469,8 @@
version = pos + 2;
else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
supported_curves = pos + 2;
+ else if (pos[0] == 'H' && pos[1] == ':' && !host)
+ host = pos + 2;
else
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: Ignore unrecognized URI parameter",
@@ -431,6 +493,7 @@
dpp_parse_uri_info(bi, info) < 0 ||
dpp_parse_uri_version(bi, version) < 0 ||
dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
+ dpp_parse_uri_host(bi, host) < 0 ||
dpp_parse_uri_pk(bi, pk) < 0) {
dpp_bootstrap_info_free(bi);
bi = NULL;
@@ -632,6 +695,7 @@
char macstr[ETH_ALEN * 2 + 10];
size_t len;
char supp_curves[10];
+ char host[100];
len = 4; /* "DPP:" */
if (bi->chan)
@@ -664,11 +728,29 @@
supp_curves[0] = '\0';
}
+ host[0] = '\0';
+ if (bi->host) {
+ char buf[100];
+ const char *addr;
+
+ addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
+ if (!addr)
+ return -1;
+ if (bi->port == DPP_TCP_PORT)
+ len += os_snprintf(host, sizeof(host), "H:%s;", addr);
+ else if (bi->host->af == AF_INET)
+ len += os_snprintf(host, sizeof(host), "H:%s:%u;",
+ addr, bi->port);
+ else
+ len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
+ addr, bi->port);
+ }
+
os_free(bi->uri);
bi->uri = os_malloc(len + 1);
if (!bi->uri)
return -1;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;",
bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
bi->chan ? ";" : "",
macstr,
@@ -677,6 +759,7 @@
DPP_VERSION == 3 ? "V:3;" :
(DPP_VERSION == 2 ? "V:2;" : ""),
supp_curves,
+ host,
bi->pk);
return 0;
}
@@ -886,7 +969,9 @@
struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
const char *name,
enum dpp_netrole netrole,
- const char *mud_url, int *opclasses)
+ const char *mud_url, int *opclasses,
+ const char *extra_name,
+ const char *extra_value)
{
size_t len, name_len;
const char *tech = "infra";
@@ -909,6 +994,8 @@
len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
if (mud_url && mud_url[0])
len += 10 + os_strlen(mud_url);
+ if (extra_name && extra_value && extra_name[0] && extra_value[0])
+ len += 10 + os_strlen(extra_name) + os_strlen(extra_value);
#ifdef CONFIG_DPP2
if (auth->csr) {
size_t csr_len;
@@ -948,6 +1035,10 @@
json_value_sep(json);
json_add_string(json, "pkcs10", csr);
}
+ if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
+ json_value_sep(json);
+ wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
+ }
json_end_object(json);
buf = dpp_build_conf_req(auth, wpabuf_head(json));
@@ -1061,6 +1152,8 @@
str_clear_free(conf->passphrase);
os_free(conf->group_id);
os_free(conf->csrattrs);
+ os_free(conf->extra_name);
+ os_free(conf->extra_value);
bin_clear_free(conf, sizeof(*conf));
}
@@ -1187,6 +1280,29 @@
os_memcpy(conf->csrattrs, pos, len);
}
+ pos = os_strstr(cmd, " conf_extra_name=");
+ if (pos) {
+ pos += 17;
+ end = os_strchr(pos, ' ');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ conf->extra_name = os_zalloc(len + 1);
+ if (!conf->extra_name)
+ goto fail;
+ os_memcpy(conf->extra_name, pos, len);
+ }
+
+ pos = os_strstr(cmd, " conf_extra_value=");
+ if (pos) {
+ pos += 18;
+ end = os_strchr(pos, ' ');
+ len = end ? (size_t) (end - pos) : os_strlen(pos);
+ len /= 2;
+ conf->extra_value = os_zalloc(len + 1);
+ if (!conf->extra_value ||
+ hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
+ goto fail;
+ }
+
if (!dpp_configuration_valid(conf))
goto fail;
@@ -1499,6 +1615,32 @@
}
+static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
+{
+ enum dpp_bootstrap_supported_curves idx;
+
+ if (!bi || !bi->supported_curves)
+ return true; /* no support indication available */
+
+ if (os_strcmp(curve, "prime256v1") == 0)
+ idx = DPP_BOOTSTRAP_CURVE_P_256;
+ else if (os_strcmp(curve, "secp384r1") == 0)
+ idx = DPP_BOOTSTRAP_CURVE_P_384;
+ else if (os_strcmp(curve, "secp521r1") == 0)
+ idx = DPP_BOOTSTRAP_CURVE_P_521;
+ else if (os_strcmp(curve, "brainpoolP256r1") == 0)
+ idx = DPP_BOOTSTRAP_CURVE_BP_256;
+ else if (os_strcmp(curve, "brainpoolP384r1") == 0)
+ idx = DPP_BOOTSTRAP_CURVE_BP_384;
+ else if (os_strcmp(curve, "brainpoolP512r1") == 0)
+ idx = DPP_BOOTSTRAP_CURVE_BP_512;
+ else
+ return true;
+
+ return bi->supported_curves & BIT(idx);
+}
+
+
static struct wpabuf *
dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
struct dpp_configuration *conf)
@@ -1520,10 +1662,23 @@
goto fail;
}
curve = auth->conf->curve;
+ if (dpp_akm_dpp(conf->akm) &&
+ !dpp_supports_curve(curve->name, auth->peer_bi)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
+ curve->name);
+ goto fail;
+ }
if (auth->new_curve && auth->new_key_received)
nak_curve = auth->new_curve;
else
nak_curve = auth->curve;
+ if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
+ nak_curve->name);
+ goto fail;
+ }
akm = conf->akm;
if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
@@ -1580,6 +1735,13 @@
if (auth->conf->net_access_key_curve &&
auth->curve != auth->conf->net_access_key_curve &&
!auth->new_key_received) {
+ if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
+ auth->peer_bi)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
+ auth->conf->net_access_key_curve->name);
+ goto fail;
+ }
wpa_printf(MSG_DEBUG,
"DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
auth->curve->name,
@@ -1642,6 +1804,9 @@
tailroom += os_strlen(auth->trusted_eap_server_name);
tailroom += 1000;
}
+ if (conf->extra_name && conf->extra_value)
+ tailroom += 10 + os_strlen(conf->extra_name) +
+ os_strlen(conf->extra_value);
buf = dpp_build_conf_start(auth, conf, tailroom);
if (!buf)
goto fail;
@@ -1702,6 +1867,11 @@
#endif /* CONFIG_DPP2 */
json_end_object(buf);
+ if (conf->extra_name && conf->extra_value) {
+ json_value_sep(buf);
+ wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
+ conf->extra_value);
+ }
json_end_object(buf);
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
@@ -1739,8 +1909,12 @@
{
struct wpabuf *buf;
const char *akm_str;
+ size_t len = 1000;
- buf = dpp_build_conf_start(auth, conf, 1000);
+ if (conf->extra_name && conf->extra_value)
+ len += 10 + os_strlen(conf->extra_name) +
+ os_strlen(conf->extra_value);
+ buf = dpp_build_conf_start(auth, conf, len);
if (!buf)
return NULL;
@@ -1753,6 +1927,11 @@
json_value_sep(buf);
dpp_build_legacy_cred_params(buf, conf);
json_end_object(buf);
+ if (conf->extra_name && conf->extra_value) {
+ json_value_sep(buf);
+ wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
+ conf->extra_value);
+ }
json_end_object(buf);
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
@@ -3972,7 +4151,7 @@
struct json_token *root = NULL, *netkey, *token;
struct json_token *own_root = NULL;
enum dpp_status_error ret = 255, res;
- struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
+ struct crypto_ec_key *own_key = NULL;
struct wpabuf *own_key_pub = NULL;
const struct dpp_curve_params *curve, *own_curve;
struct dpp_signed_connector_info info;
@@ -4045,12 +4224,12 @@
goto fail;
}
- peer_key = dpp_parse_jwk(netkey, &curve);
- if (!peer_key) {
+ intro->peer_key = dpp_parse_jwk(netkey, &curve);
+ if (!intro->peer_key) {
ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
- dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
+ dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
if (own_curve != curve) {
wpa_printf(MSG_DEBUG,
@@ -4061,7 +4240,7 @@
}
/* ECDH: N = nk * PK */
- if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
+ if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
@@ -4075,26 +4254,45 @@
intro->pmk_len = curve->hash_len;
/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
- if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
+ if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
+ 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
goto fail;
}
+#ifdef CONFIG_DPP3
+ if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
+ &intro->aead_id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
+ curve->ike_group);
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
+
ret = DPP_STATUS_OK;
fail:
if (ret != DPP_STATUS_OK)
- os_memset(intro, 0, sizeof(*intro));
+ dpp_peer_intro_deinit(intro);
os_memset(Nx, 0, sizeof(Nx));
os_free(info.payload);
crypto_ec_key_deinit(own_key);
wpabuf_free(own_key_pub);
- crypto_ec_key_deinit(peer_key);
json_free(root);
json_free(own_root);
return ret;
}
+void dpp_peer_intro_deinit(struct dpp_introduction *intro)
+{
+ if (!intro)
+ return;
+
+ crypto_ec_key_deinit(intro->peer_key);
+ os_memset(intro, 0, sizeof(*intro));
+}
+
+
#ifdef CONFIG_DPP3
int dpp_get_connector_version(const char *connector)
{
@@ -4233,7 +4431,7 @@
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
{
char *mac = NULL, *info = NULL, *curve = NULL;
- char *key = NULL, *supported_curves = NULL;
+ char *key = NULL, *supported_curves = NULL, *host = NULL;
u8 *privkey = NULL;
size_t privkey_len = 0;
int ret = -1;
@@ -4261,6 +4459,7 @@
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
supported_curves = get_param(cmd, " supported_curves=");
+ host = get_param(cmd, " host=");
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -4275,6 +4474,7 @@
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
+ dpp_parse_uri_host(bi, host) < 0 ||
dpp_gen_uri(bi) < 0)
goto fail;
@@ -4288,6 +4488,7 @@
os_free(info);
str_clear_free(key);
os_free(supported_curves);
+ os_free(host);
bin_clear_free(privkey, privkey_len);
dpp_bootstrap_info_free(bi);
return ret;
@@ -4343,6 +4544,8 @@
struct dpp_bootstrap_info *bi;
char pkhash[2 * SHA256_MAC_LEN + 1];
char supp_curves[100];
+ char host[100];
+ int ret;
bi = dpp_bootstrap_get_id(dpp, id);
if (!bi)
@@ -4352,7 +4555,6 @@
supp_curves[0] = '\0';
if (bi->supported_curves) {
- int ret;
size_t i;
char *pos = supp_curves;
char *end = &supp_curves[sizeof(supp_curves)];
@@ -4379,6 +4581,17 @@
supp_curves[0] = '\0';
}
+ host[0] = '\0';
+ if (bi->host) {
+ char buf[100];
+
+ ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
+ hostapd_ip_txt(bi->host, buf, sizeof(buf)),
+ bi->port);
+ if (os_snprintf_error(sizeof(host), ret))
+ return -1;
+ }
+
return os_snprintf(reply, reply_size, "type=%s\n"
"mac_addr=" MACSTR "\n"
"info=%s\n"
@@ -4386,7 +4599,7 @@
"use_freq=%u\n"
"curve=%s\n"
"pkhash=%s\n"
- "version=%d\n%s",
+ "version=%d\n%s%s",
dpp_bootstrap_type_txt(bi->type),
MAC2STR(bi->mac_addr),
bi->info ? bi->info : "",
@@ -4395,7 +4608,8 @@
bi->curve->name,
pkhash,
bi->version,
- supp_curves);
+ supp_curves,
+ host);
}
@@ -4796,6 +5010,7 @@
#ifdef CONFIG_DPP2
dl_list_init(&dpp->controllers);
dl_list_init(&dpp->tcp_init);
+ dpp->relay_sock = -1;
#endif /* CONFIG_DPP2 */
return dpp;
@@ -4856,3 +5071,98 @@
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+
+struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
+{
+ struct wpabuf *msg;
+ const u8 *r_hash = bi->pubkey_hash_chirp;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Build Push Button Presence Announcement frame");
+
+ msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
+ 4 + SHA256_MAC_LEN);
+ if (!msg)
+ return NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ r_hash = test_hash;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Push Button Presence Announcement frame attributes",
+ msg);
+ return msg;
+}
+
+
+struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
+ const u8 *e_hash,
+ const u8 *c_nonce,
+ size_t c_nonce_len)
+{
+ struct wpabuf *msg;
+ const u8 *i_hash = bi->pubkey_hash_chirp;
+#ifdef CONFIG_TESTING_OPTIONS
+ u8 test_hash[SHA256_MAC_LEN];
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Build Push Button Presence Announcement Response frame");
+
+ msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
+ 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
+ if (!msg)
+ return NULL;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid I-Bootstrap Key Hash");
+ os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ i_hash = test_hash;
+ } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
+ wpa_printf(MSG_INFO,
+ "DPP: TESTING - invalid R-Bootstrap Key Hash");
+ os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
+ test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
+ e_hash = test_hash;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Initiator Bootstrapping Key Hash */
+ wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
+ wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
+ wpabuf_put_le16(msg, SHA256_MAC_LEN);
+ wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
+
+ /* Responder Bootstrapping Key Hash */
+ dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
+
+ /* Configurator Nonce */
+ wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
+ wpabuf_put_le16(msg, c_nonce_len);
+ wpabuf_put_data(msg, c_nonce, c_nonce_len);
+
+ wpa_hexdump_buf(MSG_DEBUG,
+ "DPP: Push Button Presence Announcement Response frame attributes",
+ msg);
+ return msg;
+}
+
+#endif /* CONFIG_DPP3 */
diff --git a/src/common/dpp.h b/src/common/dpp.h
index fba4119..ee29a08 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -56,6 +56,11 @@
DPP_PA_RECONFIG_AUTH_RESP = 16,
DPP_PA_RECONFIG_AUTH_CONF = 17,
DPP_PA_PKEX_EXCHANGE_REQ = 18,
+ DPP_PA_PB_PRESENCE_ANNOUNCEMENT = 19,
+ DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP = 20,
+ DPP_PA_PRIV_PEER_INTRO_QUERY = 21,
+ DPP_PA_PRIV_PEER_INTRO_NOTIFY = 22,
+ DPP_PA_PRIV_PEER_INTRO_UPDATE = 23,
};
enum dpp_attribute_id {
@@ -163,6 +168,8 @@
u8 mac_addr[ETH_ALEN];
char *chan;
char *info;
+ struct hostapd_ip_addr *host;
+ unsigned int port;
char *pk;
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
unsigned int num_freq;
@@ -179,6 +186,9 @@
int nfc_negotiated; /* whether this has been used in NFC negotiated
* connection handover */
char *configurator_params;
+ u8 peer_pubkey_hash[SHA256_MAC_LEN]; /* for enforcing a specific
+ * peer bootstrapping key with
+ * PKEX */
};
#define PKEX_COUNTER_T_LIMIT 5
@@ -201,6 +211,7 @@
u8 peer_mac[ETH_ALEN];
char *identifier;
char *code;
+ size_t code_len;
struct crypto_ec_key *x;
struct crypto_ec_key *y;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
@@ -214,6 +225,7 @@
unsigned int exch_req_tries;
unsigned int freq;
u8 peer_version;
+ struct wpabuf *enc_key;
};
enum dpp_akm {
@@ -252,6 +264,8 @@
int psk_set;
char *csrattrs;
+ char *extra_name;
+ char *extra_value;
};
struct dpp_asymmetric_key {
@@ -409,6 +423,10 @@
u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
int peer_version;
+ struct crypto_ec_key *peer_key;
+ enum hpke_kem_id kem_id;
+ enum hpke_kdf_id kdf_id;
+ enum hpke_aead_id aead_id;
};
struct dpp_relay_config {
@@ -435,6 +453,13 @@
bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth);
};
+#define DPP_PB_INFO_COUNT 2
+
+struct dpp_pb_info {
+ u8 hash[SHA256_MAC_LEN];
+ struct os_reltime rx_time;
+};
+
#ifdef CONFIG_TESTING_OPTIONS
enum dpp_test_behavior {
DPP_TEST_DISABLED = 0,
@@ -535,6 +560,9 @@
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP = 95,
DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 96,
DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 97,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ = 98,
+ DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP = 99,
+ DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP = 100,
};
extern enum dpp_test_behavior dpp_test;
@@ -581,7 +609,9 @@
struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
const char *name,
enum dpp_netrole netrole,
- const char *mud_url, int *opclasses);
+ const char *mud_url, int *opclasses,
+ const char *extra_name,
+ const char *extra_value);
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len);
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
@@ -589,6 +619,8 @@
void dpp_controller_pkex_add(struct dpp_global *dpp,
struct dpp_bootstrap_info *bi,
const char *code, const char *identifier);
+bool dpp_controller_is_own_pkex_req(struct dpp_global *dpp,
+ const u8 *buf, size_t len);
struct dpp_configuration * dpp_configuration_alloc(const char *type);
int dpp_akm_psk(enum dpp_akm akm);
int dpp_akm_sae(enum dpp_akm akm);
@@ -641,17 +673,18 @@
const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len,
os_time_t *expiry);
+void dpp_peer_intro_deinit(struct dpp_introduction *intro);
int dpp_get_connector_version(const char *connector);
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const char *identifier, const char *code,
- bool v2);
+ size_t code_len, bool v2);
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const u8 *peer_mac,
const char *identifier,
- const char *code,
+ const char *code, size_t code_len,
const u8 *buf, size_t len, bool v2);
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
const u8 *peer_mac,
@@ -678,6 +711,11 @@
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
void dpp_pfs_free(struct dpp_pfs *pfs);
+struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len);
+int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
+ enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id);
+
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
const char *name);
int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
@@ -714,12 +752,18 @@
const u8 *kid);
int dpp_relay_add_controller(struct dpp_global *dpp,
struct dpp_relay_config *config);
+void dpp_relay_remove_controller(struct dpp_global *dpp,
+ const struct hostapd_ip_addr *addr);
+int dpp_relay_listen(struct dpp_global *dpp, int port,
+ struct dpp_relay_config *config);
+void dpp_relay_stop_listen(struct dpp_global *dpp);
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
const u8 *buf, size_t len, unsigned int freq,
const u8 *i_bootstrap, const u8 *r_bootstrap,
void *cb_ctx);
int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
size_t data_len);
+bool dpp_relay_controller_available(struct dpp_global *dpp);
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
int dpp_controller_set_params(struct dpp_global *dpp,
@@ -737,15 +781,20 @@
struct dpp_bootstrap_info *bi));
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
const struct hostapd_ip_addr *addr, int port,
- const char *name, enum dpp_netrole netrole, void *msg_ctx,
- void *cb_ctx,
+ const char *name, enum dpp_netrole netrole,
+ const char *mud_url,
+ const char *extra_conf_req_name,
+ const char *extra_conf_req_value,
+ void *msg_ctx, void *cb_ctx,
int (*process_conf_obj)(void *ctx,
struct dpp_authentication *auth),
bool (*tcp_msg_sent)(void *ctx,
struct dpp_authentication *auth));
int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
struct dpp_authentication *auth, const char *name,
- enum dpp_netrole netrole,
+ enum dpp_netrole netrole, const char *mud_url,
+ const char *extra_conf_req_name,
+ const char *extra_conf_req_value,
int (*process_conf_obj)(void *ctx,
struct dpp_authentication *auth),
bool (*tcp_msg_sent)(void *ctx,
@@ -760,6 +809,12 @@
void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
unsigned int freq, const u8 *hash);
+struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi);
+struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
+ const u8 *e_hash,
+ const u8 *c_nonce,
+ size_t c_nonce_len);
+
struct dpp_global_config {
void *cb_ctx;
void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 47f56c2..09d4d8c 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -1035,10 +1035,9 @@
int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
{
struct crypto_ec *ec;
- struct crypto_ec_point *L = NULL;
- const struct crypto_ec_point *BI;
- const struct crypto_bignum *bR, *pR, *q;
- struct crypto_bignum *sum = NULL, *lx = NULL;
+ struct crypto_ec_point *L = NULL, *BI = NULL;
+ const struct crypto_bignum *q;
+ struct crypto_bignum *sum = NULL, *lx = NULL, *bR = NULL, *pR = NULL;
int ret = -1;
/* L = ((bR + pR) modulo q) * BI */
@@ -1068,7 +1067,10 @@
fail:
crypto_bignum_deinit(lx, 1);
crypto_bignum_deinit(sum, 1);
+ crypto_bignum_deinit(bR, 1);
+ crypto_bignum_deinit(pR, 1);
crypto_ec_point_deinit(L, 1);
+ crypto_ec_point_deinit(BI, 1);
crypto_ec_deinit(ec);
return ret;
}
@@ -1077,10 +1079,8 @@
int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
{
struct crypto_ec *ec;
- struct crypto_ec_point *L = NULL, *sum = NULL;
- const struct crypto_ec_point *BR, *PR;
- const struct crypto_bignum *bI;
- struct crypto_bignum *lx = NULL;
+ struct crypto_ec_point *L = NULL, *sum = NULL, *BR = NULL, *PR = NULL;
+ struct crypto_bignum *lx = NULL, *bI = NULL;
int ret = -1;
/* L = bI * (BR + PR) */
@@ -1108,8 +1108,11 @@
ret = 0;
fail:
crypto_bignum_deinit(lx, 1);
+ crypto_bignum_deinit(bI, 1);
crypto_ec_point_deinit(sum, 1);
crypto_ec_point_deinit(L, 1);
+ crypto_ec_point_deinit(BR, 1);
+ crypto_ec_point_deinit(PR, 1);
crypto_ec_deinit(ec);
return ret;
}
@@ -1434,16 +1437,15 @@
struct crypto_ec_point *
dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec)
{
u8 hash[DPP_MAX_HASH_LEN];
const u8 *addr[3];
size_t len[3];
unsigned int num_elem = 0;
- struct crypto_ec_point *Qi = NULL;
+ struct crypto_ec_point *Qi = NULL, *Pi = NULL;
struct crypto_ec_key *Pi_key = NULL;
- const struct crypto_ec_point *Pi = NULL;
struct crypto_bignum *hash_bn = NULL;
struct crypto_ec *ec = NULL;
@@ -1463,9 +1465,9 @@
len[num_elem] = os_strlen(identifier);
num_elem++;
}
- wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
addr[num_elem] = (const u8 *) code;
- len[num_elem] = os_strlen(code);
+ len[num_elem] = code_len;
num_elem++;
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
goto fail;
@@ -1494,6 +1496,7 @@
crypto_ec_point_debug_print(ec, Qi, "DPP: Qi");
out:
crypto_ec_key_deinit(Pi_key);
+ crypto_ec_point_deinit(Pi, 1);
crypto_bignum_deinit(hash_bn, 1);
if (ret_ec && Qi)
*ret_ec = ec;
@@ -1509,16 +1512,15 @@
struct crypto_ec_point *
dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec)
{
u8 hash[DPP_MAX_HASH_LEN];
const u8 *addr[3];
size_t len[3];
unsigned int num_elem = 0;
- struct crypto_ec_point *Qr = NULL;
+ struct crypto_ec_point *Qr = NULL, *Pr = NULL;
struct crypto_ec_key *Pr_key = NULL;
- const struct crypto_ec_point *Pr = NULL;
struct crypto_bignum *hash_bn = NULL;
struct crypto_ec *ec = NULL;
@@ -1538,9 +1540,9 @@
len[num_elem] = os_strlen(identifier);
num_elem++;
}
- wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
+ wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
addr[num_elem] = (const u8 *) code;
- len[num_elem] = os_strlen(code);
+ len[num_elem] = code_len;
num_elem++;
if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
goto fail;
@@ -1570,6 +1572,7 @@
out:
crypto_ec_key_deinit(Pr_key);
+ crypto_ec_point_deinit(Pr, 1);
crypto_bignum_deinit(hash_bn, 1);
if (ret_ec && Qr)
*ret_ec = ec;
@@ -1587,7 +1590,7 @@
u8 ver_init, u8 ver_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
- const char *code,
+ const char *code, size_t code_len,
const u8 *Kx, size_t Kx_len,
u8 *z, unsigned int hash_len)
{
@@ -1612,7 +1615,7 @@
info_len = 2 * ETH_ALEN;
else
info_len = 2;
- info_len += Mx_len + Nx_len + os_strlen(code);
+ info_len += Mx_len + Nx_len + code_len;
info = os_malloc(info_len);
if (!info)
return -1;
@@ -1630,7 +1633,7 @@
pos += Mx_len;
os_memcpy(pos, Nx, Nx_len);
pos += Nx_len;
- os_memcpy(pos, code, os_strlen(code));
+ os_memcpy(pos, code, code_len);
/* HKDF-Expand(PRK, info, L) */
if (hash_len == 32)
@@ -1661,11 +1664,10 @@
struct json_token *peer_net_access_key)
{
struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
- struct crypto_bignum *sum = NULL;
- const struct crypto_bignum *q, *cR, *pR;
+ struct crypto_bignum *sum = NULL, *cR = NULL, *pR = NULL;
+ const struct crypto_bignum *q;
struct crypto_ec *ec = NULL;
- struct crypto_ec_point *M = NULL;
- const struct crypto_ec_point *CI;
+ struct crypto_ec_point *M = NULL, *CI = NULL;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
u8 prk[DPP_MAX_HASH_LEN];
const struct dpp_curve_params *curve;
@@ -1748,7 +1750,10 @@
forced_memzero(prk, sizeof(prk));
forced_memzero(Mx, sizeof(Mx));
crypto_ec_point_deinit(M, 1);
+ crypto_ec_point_deinit(CI, 1);
crypto_bignum_deinit(sum, 1);
+ crypto_bignum_deinit(cR, 1);
+ crypto_bignum_deinit(pR, 1);
crypto_ec_key_deinit(own_key);
crypto_ec_key_deinit(peer_key);
crypto_ec_deinit(ec);
@@ -1761,10 +1766,9 @@
struct json_token *net_access_key)
{
struct crypto_ec_key *pr = NULL, *peer_key = NULL;
- const struct crypto_ec_point *CR, *PR;
- const struct crypto_bignum *cI;
+ struct crypto_bignum *cI = NULL;
struct crypto_ec *ec = NULL;
- struct crypto_ec_point *sum = NULL, *M = NULL;
+ struct crypto_ec_point *sum = NULL, *M = NULL, *CR = NULL, *PR = NULL;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
u8 prk[DPP_MAX_HASH_LEN];
int res = -1;
@@ -1835,10 +1839,13 @@
fail:
forced_memzero(prk, sizeof(prk));
forced_memzero(Mx, sizeof(Mx));
+ crypto_bignum_deinit(cI, 1);
crypto_ec_key_deinit(pr);
crypto_ec_key_deinit(peer_key);
crypto_ec_point_deinit(sum, 1);
crypto_ec_point_deinit(M, 1);
+ crypto_ec_point_deinit(CR, 1);
+ crypto_ec_point_deinit(PR, 1);
crypto_ec_deinit(ec);
return res;
}
@@ -2259,8 +2266,8 @@
{
const struct crypto_bignum *q;
struct crypto_bignum *bn;
- const struct crypto_ec_point *pp, *generator;
- struct crypto_ec_point *e_prime_id, *a_nonce;
+ const struct crypto_ec_point *generator;
+ struct crypto_ec_point *e_prime_id, *a_nonce, *pp;
int ret = -1;
pp = crypto_ec_key_get_public_key(id->pp_key);
@@ -2297,6 +2304,7 @@
fail:
crypto_ec_point_deinit(e_prime_id, 1);
crypto_ec_point_deinit(a_nonce, 1);
+ crypto_ec_point_deinit(pp, 1);
crypto_bignum_deinit(bn, 1);
return ret;
}
@@ -2321,9 +2329,9 @@
struct crypto_ec_key *e_prime_id)
{
struct crypto_ec *ec;
- const struct crypto_bignum *pp;
+ struct crypto_bignum *pp = NULL;
struct crypto_ec_point *e_id = NULL;
- const struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
+ struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
if (!ppkey)
return NULL;
@@ -2348,6 +2356,9 @@
crypto_ec_point_debug_print(ec, e_id, "DPP: Decrypted E-id");
fail:
+ crypto_ec_point_deinit(a_nonce_point, 1);
+ crypto_ec_point_deinit(e_prime_id_point, 1);
+ crypto_bignum_deinit(pp, 1);
crypto_ec_deinit(ec);
return e_id;
}
@@ -2356,6 +2367,7 @@
#ifdef CONFIG_DPP3
+
int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i)
{
int ret = -1, res;
@@ -2443,6 +2455,47 @@
wpabuf_free(pex);
return ret;
}
+
+
+int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
+ enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id)
+{
+ switch (iana_group) {
+ case 19:
+ *kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
+ *kdf_id = HPKE_KDF_HKDF_SHA256;
+ *aead_id = HPKE_AEAD_AES_128_GCM;
+ return 0;
+ case 20:
+ *kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
+ *kdf_id = HPKE_KDF_HKDF_SHA384;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ case 21:
+ *kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
+ *kdf_id = HPKE_KDF_HKDF_SHA512;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ case 28:
+ *kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
+ *kdf_id = HPKE_KDF_HKDF_SHA256;
+ *aead_id = HPKE_AEAD_AES_128_GCM;
+ return 0;
+ case 29:
+ *kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
+ *kdf_id = HPKE_KDF_HKDF_SHA384;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ case 30:
+ *kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
+ *kdf_id = HPKE_KDF_HKDF_SHA512;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ }
+
+ return -1;
+}
+
#endif /* CONFIG_DPP3 */
@@ -2453,8 +2506,7 @@
{
struct crypto_ec *ec;
struct crypto_ec_key *key = NULL;
- const struct crypto_ec_point *pub_key;
- struct crypto_ec_point *p = NULL;
+ struct crypto_ec_point *p = NULL, *pub_key = NULL;
u8 *x, *y;
int ret = -1;
@@ -2472,11 +2524,9 @@
/* Retrieve public key coordinates */
pub_key = crypto_ec_key_get_public_key(key);
- if (!pub_key)
+ if (!pub_key || crypto_ec_point_to_bin(ec, pub_key, x, y))
goto fail;
- crypto_ec_point_to_bin(ec, pub_key, x, y);
-
/* And corrupt them */
y[curve->prime_len - 1] ^= 0x01;
p = crypto_ec_point_from_bin(ec, x);
@@ -2489,6 +2539,7 @@
ret = 0;
fail:
crypto_ec_point_deinit(p, 0);
+ crypto_ec_point_deinit(pub_key, 0);
crypto_ec_key_deinit(key);
crypto_ec_deinit(ec);
return ret;
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index 10db4e8..dfa4a3c 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -19,8 +19,16 @@
struct dl_list configurator; /* struct dpp_configurator */
#ifdef CONFIG_DPP2
struct dl_list controllers; /* struct dpp_relay_controller */
+ struct dpp_relay_controller *tmp_controller;
struct dpp_controller *controller;
struct dl_list tcp_init; /* struct dpp_connection */
+ int relay_sock;
+ void *relay_msg_ctx;
+ void *relay_cb_ctx;
+ void (*relay_tx)(void *ctx, const u8 *addr, unsigned int freq,
+ const u8 *msg, size_t len);
+ void (*relay_gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
+ int prot, struct wpabuf *buf);
void *cb_ctx;
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth);
@@ -97,8 +105,6 @@
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
const u8 *privkey, size_t privkey_len);
-struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
- const u8 *privkey, size_t privkey_len);
struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve);
int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
@@ -113,17 +119,17 @@
struct crypto_ec_key *peer_key, u8 *pmkid);
struct crypto_ec_point *
dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec);
struct crypto_ec_point *
dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
- const char *code, const char *identifier,
+ const char *code, size_t code_len, const char *identifier,
struct crypto_ec **ret_ec);
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
u8 ver_init, u8 ver_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
- const char *code,
+ const char *code, size_t code_len,
const u8 *Kx, size_t Kx_len,
u8 *z, unsigned int hash_len);
int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c
index 72084d9..dca0d8d 100644
--- a/src/common/dpp_pkex.c
+++ b/src/common/dpp_pkex.c
@@ -30,8 +30,7 @@
bool v2)
{
struct crypto_ec *ec = NULL;
- const struct crypto_ec_point *X;
- struct crypto_ec_point *Qi = NULL, *M = NULL;
+ struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL;
u8 *Mx, *My;
struct wpabuf *msg = NULL;
size_t attr_len;
@@ -42,7 +41,7 @@
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
- pkex->identifier, &ec);
+ pkex->code_len, pkex->identifier, &ec);
if (!Qi)
goto fail;
@@ -146,10 +145,13 @@
My = wpabuf_put(msg, curve->prime_len);
if (crypto_ec_point_to_bin(ec, M, Mx, My))
goto fail;
+ wpabuf_free(pkex->enc_key);
+ pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len);
os_memcpy(pkex->Mx, Mx, curve->prime_len);
out:
+ crypto_ec_point_deinit(X, 1);
crypto_ec_point_deinit(M, 1);
crypto_ec_point_deinit(Qi, 1);
crypto_ec_deinit(ec);
@@ -171,7 +173,7 @@
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
const char *identifier, const char *code,
- bool v2)
+ size_t code_len, bool v2)
{
struct dpp_pkex *pkex;
@@ -196,9 +198,10 @@
if (!pkex->identifier)
goto fail;
}
- pkex->code = os_strdup(code);
+ pkex->code = os_memdup(code, code_len);
if (!pkex->code)
goto fail;
+ pkex->code_len = code_len;
pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
if (!pkex->exchange_req)
goto fail;
@@ -340,7 +343,7 @@
const u8 *own_mac,
const u8 *peer_mac,
const char *identifier,
- const char *code,
+ const char *code, size_t code_len,
const u8 *buf, size_t len, bool v2)
{
const u8 *attr_group, *attr_id, *attr_key;
@@ -349,9 +352,8 @@
u16 ike_group;
struct dpp_pkex *pkex = NULL;
struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
- *N = NULL;
+ *N = NULL, *Y = NULL;
struct crypto_ec *ec = NULL;
- const struct crypto_ec_point *Y;
u8 *x_coord = NULL, *y_coord = NULL;
u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
size_t Kx_len;
@@ -438,8 +440,8 @@
}
/* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
- Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
- &ec);
+ Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len,
+ identifier, &ec);
if (!Qi)
goto fail;
@@ -478,9 +480,10 @@
if (!pkex->identifier)
goto fail;
}
- pkex->code = os_strdup(code);
+ pkex->code = os_memdup(code, code_len);
if (!pkex->code)
goto fail;
+ pkex->code_len = code_len;
os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
@@ -496,8 +499,8 @@
goto fail;
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
- Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier,
- NULL);
+ Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len,
+ identifier, NULL);
if (!Qr)
goto fail;
@@ -551,7 +554,8 @@
pkex->peer_version, DPP_VERSION,
pkex->Mx, curve->prime_len,
pkex->Nx, curve->prime_len, pkex->code,
- Kx, Kx_len, pkex->z, curve->hash_len);
+ pkex->code_len, Kx, Kx_len, pkex->z,
+ curve->hash_len);
os_memset(Kx, 0, Kx_len);
if (res < 0)
goto fail;
@@ -566,6 +570,7 @@
crypto_ec_point_deinit(M, 1);
crypto_ec_point_deinit(N, 1);
crypto_ec_point_deinit(X, 1);
+ crypto_ec_point_deinit(Y, 1);
crypto_ec_deinit(ec);
return pkex;
fail:
@@ -791,7 +796,8 @@
/* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
- pkex->code, pkex->identifier, &ec);
+ pkex->code, pkex->code_len, pkex->identifier,
+ &ec);
if (!Qr)
goto fail;
@@ -869,7 +875,7 @@
DPP_VERSION, pkex->peer_version,
pkex->Mx, curve->prime_len,
attr_key /* N.x */, attr_key_len / 2,
- pkex->code, Kx, Kx_len,
+ pkex->code, pkex->code_len, Kx, Kx_len,
pkex->z, curve->hash_len);
os_memset(Kx, 0, Kx_len);
if (res < 0)
@@ -1357,6 +1363,8 @@
dpp_bootstrap_info_free(bi);
return NULL;
}
+ os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash,
+ SHA256_MAC_LEN);
dpp_pkex_free(pkex);
dl_list_add(&dpp->bootstrap, &bi->list);
return bi;
@@ -1375,5 +1383,6 @@
crypto_ec_key_deinit(pkex->peer_bootstrap_key);
wpabuf_free(pkex->exchange_req);
wpabuf_free(pkex->exchange_resp);
+ wpabuf_free(pkex->enc_key);
os_free(pkex);
}
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index c83fb2d..ff18a99 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -48,6 +48,9 @@
unsigned int gas_comeback_in_progress:1;
u8 gas_dialog_token;
char *name;
+ char *mud_url;
+ char *extra_conf_req_name;
+ char *extra_conf_req_value;
enum dpp_netrole netrole;
};
@@ -118,6 +121,9 @@
dpp_auth_deinit(conn->auth);
dpp_pkex_free(conn->pkex);
os_free(conn->name);
+ os_free(conn->mud_url);
+ os_free(conn->extra_conf_req_name);
+ os_free(conn->extra_conf_req_value);
os_free(conn);
}
@@ -133,6 +139,7 @@
struct dpp_relay_config *config)
{
struct dpp_relay_controller *ctrl;
+ char txt[100];
if (!dpp)
return -1;
@@ -148,6 +155,8 @@
ctrl->cb_ctx = config->cb_ctx;
ctrl->tx = config->tx;
ctrl->gas_resp_tx = config->gas_resp_tx;
+ wpa_printf(MSG_DEBUG, "DPP: Add Relay connection to Controller %s",
+ hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
dl_list_add(&dpp->controllers, &ctrl->list);
return 0;
}
@@ -189,6 +198,31 @@
}
+static struct dpp_relay_controller *
+dpp_relay_controller_get_addr(struct dpp_global *dpp,
+ const struct sockaddr_in *addr)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return NULL;
+
+ dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
+ list) {
+ if (ctrl->ipaddr.af == AF_INET &&
+ addr->sin_addr.s_addr == ctrl->ipaddr.u.v4.s_addr)
+ return ctrl;
+ }
+
+ if (dpp->tmp_controller &&
+ dpp->tmp_controller->ipaddr.af == AF_INET &&
+ addr->sin_addr.s_addr == dpp->tmp_controller->ipaddr.u.v4.s_addr)
+ return dpp->tmp_controller;
+
+ return NULL;
+}
+
+
static void dpp_controller_gas_done(struct dpp_connection *conn)
{
struct dpp_authentication *auth = conn->auth;
@@ -214,7 +248,8 @@
return;
}
- wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d",
+ auth->conf_resp_status);
dpp_connection_remove(conn);
}
@@ -312,8 +347,10 @@
const char *dpp_name;
dpp_name = conn->name ? conn->name : "Test";
- buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, NULL,
- NULL);
+ buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole,
+ conn->mud_url, NULL,
+ conn->extra_conf_req_name,
+ conn->extra_conf_req_value);
if (!buf) {
wpa_printf(MSG_DEBUG,
"DPP: No configuration request data available");
@@ -520,6 +557,31 @@
}
+static struct dpp_connection *
+dpp_relay_match_ctrl(struct dpp_relay_controller *ctrl, const u8 *src,
+ unsigned int freq, u8 type)
+{
+ struct dpp_connection *conn;
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ if (os_memcmp(src, conn->mac_addr, ETH_ALEN) == 0)
+ return conn;
+ if ((type == DPP_PA_PKEX_EXCHANGE_RESP ||
+ type == DPP_PA_AUTHENTICATION_RESP) &&
+ conn->freq == 0 &&
+ is_broadcast_ether_addr(conn->mac_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Associate this peer to the new Controller initiated connection");
+ os_memcpy(conn->mac_addr, src, ETH_ALEN);
+ conn->freq = freq;
+ return conn;
+ }
+ }
+
+ return NULL;
+}
+
+
int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
const u8 *buf, size_t len, unsigned int freq,
const u8 *i_bootstrap, const u8 *r_bootstrap,
@@ -538,12 +600,16 @@
type != DPP_PA_RECONFIG_ANNOUNCEMENT) {
dl_list_for_each(ctrl, &dpp->controllers,
struct dpp_relay_controller, list) {
- dl_list_for_each(conn, &ctrl->conn,
- struct dpp_connection, list) {
- if (os_memcmp(src, conn->mac_addr,
- ETH_ALEN) == 0)
- return dpp_relay_tx(conn, hdr, buf, len);
- }
+ conn = dpp_relay_match_ctrl(ctrl, src, freq, type);
+ if (conn)
+ return dpp_relay_tx(conn, hdr, buf, len);
+ }
+
+ if (dpp->tmp_controller) {
+ conn = dpp_relay_match_ctrl(dpp->tmp_controller, src,
+ freq, type);
+ if (conn)
+ return dpp_relay_tx(conn, hdr, buf, len);
}
}
@@ -579,11 +645,25 @@
}
+static struct dpp_connection *
+dpp_relay_find_conn(struct dpp_relay_controller *ctrl, const u8 *src)
+{
+ struct dpp_connection *conn;
+
+ dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) {
+ if (os_memcmp(src, conn->mac_addr, ETH_ALEN) == 0)
+ return conn;
+ }
+
+ return NULL;
+}
+
+
int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
size_t data_len)
{
struct dpp_relay_controller *ctrl;
- struct dpp_connection *conn, *found = NULL;
+ struct dpp_connection *conn = NULL;
struct wpabuf *msg;
/* Check if there is a successfully completed authentication for this
@@ -591,19 +671,15 @@
*/
dl_list_for_each(ctrl, &dpp->controllers,
struct dpp_relay_controller, list) {
- if (found)
+ conn = dpp_relay_find_conn(ctrl, src);
+ if (conn)
break;
- dl_list_for_each(conn, &ctrl->conn,
- struct dpp_connection, list) {
- if (os_memcmp(src, conn->mac_addr,
- ETH_ALEN) == 0) {
- found = conn;
- break;
- }
- }
}
- if (!found)
+ if (!conn && dpp->tmp_controller)
+ conn = dpp_relay_find_conn(dpp->tmp_controller, src);
+
+ if (!conn)
return -1;
msg = wpabuf_alloc(4 + 1 + data_len);
@@ -622,6 +698,12 @@
}
+bool dpp_relay_controller_available(struct dpp_global *dpp)
+{
+ return dpp && dl_list_len(&dpp->controllers) > 0;
+}
+
+
static void dpp_controller_free(struct dpp_controller *ctrl)
{
struct dpp_connection *conn, *tmp;
@@ -799,8 +881,9 @@
status = dpp_conf_result_rx(auth, hdr, buf, len);
if (status == DPP_STATUS_OK && auth->send_conn_status) {
- wpa_msg(msg_ctx, MSG_INFO,
- DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT
+ "wait_conn_status=1 conf_resp_status=%d",
+ auth->conf_resp_status);
wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
auth->waiting_conn_status_result = 1;
eloop_cancel_timeout(
@@ -812,7 +895,8 @@
return 0;
}
if (status == DPP_STATUS_OK)
- wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT
+ "conf_resp_status=%d", auth->conf_resp_status);
else
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
return -1; /* to remove the completed connection */
@@ -1017,6 +1101,7 @@
NULL, NULL,
ctrl->pkex_identifier,
ctrl->pkex_code,
+ os_strlen(ctrl->pkex_code),
buf, len, true);
if (!conn->pkex) {
wpa_printf(MSG_DEBUG,
@@ -1307,6 +1392,8 @@
return -1;
}
+ wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX);
+
pos = msg;
end = msg + len;
@@ -1911,7 +1998,10 @@
int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
const struct hostapd_ip_addr *addr, int port, const char *name,
- enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx,
+ enum dpp_netrole netrole, const char *mud_url,
+ const char *extra_conf_req_name,
+ const char *extra_conf_req_value,
+ void *msg_ctx, void *cb_ctx,
int (*process_conf_obj)(void *ctx,
struct dpp_authentication *auth),
bool (*tcp_msg_sent)(void *ctx,
@@ -1941,6 +2031,12 @@
conn->process_conf_obj = process_conf_obj;
conn->tcp_msg_sent = tcp_msg_sent;
conn->name = os_strdup(name ? name : "Test");
+ if (mud_url)
+ conn->mud_url = os_strdup(mud_url);
+ if (extra_conf_req_name)
+ conn->extra_conf_req_name = os_strdup(extra_conf_req_name);
+ if (extra_conf_req_value)
+ conn->extra_conf_req_value = os_strdup(extra_conf_req_value);
conn->netrole = netrole;
conn->global = dpp;
conn->auth = auth;
@@ -1987,7 +2083,9 @@
int dpp_tcp_auth(struct dpp_global *dpp, void *_conn,
struct dpp_authentication *auth, const char *name,
- enum dpp_netrole netrole,
+ enum dpp_netrole netrole, const char *mud_url,
+ const char *extra_conf_req_name,
+ const char *extra_conf_req_value,
int (*process_conf_obj)(void *ctx,
struct dpp_authentication *auth),
bool (*tcp_msg_sent)(void *ctx,
@@ -2001,6 +2099,13 @@
conn->tcp_msg_sent = tcp_msg_sent;
os_free(conn->name);
conn->name = os_strdup(name ? name : "Test");
+ os_free(conn->mud_url);
+ conn->mud_url = mud_url ? os_strdup(mud_url) : NULL;
+ os_free(conn->extra_conf_req_name);
+ conn->extra_conf_req_name = extra_conf_req_name ?
+ os_strdup(extra_conf_req_name) : NULL;
+ conn->extra_conf_req_value = extra_conf_req_value ?
+ os_strdup(extra_conf_req_value) : NULL;
conn->netrole = netrole;
conn->auth = auth;
@@ -2203,6 +2308,35 @@
}
+bool dpp_controller_is_own_pkex_req(struct dpp_global *dpp,
+ const u8 *buf, size_t len)
+{
+ struct dpp_connection *conn;
+ const u8 *attr_key = NULL;
+ u16 attr_key_len = 0;
+
+ dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) {
+ if (!conn->pkex || !conn->pkex->enc_key)
+ continue;
+
+ if (!attr_key) {
+ attr_key = dpp_get_attr(buf, len,
+ DPP_ATTR_ENCRYPTED_KEY,
+ &attr_key_len);
+ if (!attr_key)
+ return false;
+ }
+
+ if (attr_key_len == wpabuf_len(conn->pkex->enc_key) &&
+ os_memcmp(attr_key, wpabuf_head(conn->pkex->enc_key),
+ attr_key_len) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
void dpp_tcp_init_flush(struct dpp_global *dpp)
{
struct dpp_connection *conn, *tmp;
@@ -2216,6 +2350,10 @@
static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
{
struct dpp_connection *conn, *tmp;
+ char txt[100];
+
+ wpa_printf(MSG_DEBUG, "DPP: Remove Relay connection to Controller %s",
+ hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
list)
@@ -2236,6 +2374,204 @@
dl_list_del(&ctrl->list);
dpp_relay_controller_free(ctrl);
}
+
+ if (dpp->tmp_controller) {
+ dpp_relay_controller_free(dpp->tmp_controller);
+ dpp->tmp_controller = NULL;
+ }
+}
+
+
+void dpp_relay_remove_controller(struct dpp_global *dpp,
+ const struct hostapd_ip_addr *addr)
+{
+ struct dpp_relay_controller *ctrl;
+
+ if (!dpp)
+ return;
+
+ dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
+ list) {
+ if (hostapd_ip_equal(&ctrl->ipaddr, addr)) {
+ dl_list_del(&ctrl->list);
+ dpp_relay_controller_free(ctrl);
+ return;
+ }
+ }
+
+ if (dpp->tmp_controller &&
+ hostapd_ip_equal(&dpp->tmp_controller->ipaddr, addr)) {
+ dpp_relay_controller_free(dpp->tmp_controller);
+ dpp->tmp_controller = NULL;
+ }
+}
+
+
+static void dpp_relay_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct dpp_global *dpp = eloop_ctx;
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(addr);
+ int fd;
+ struct dpp_relay_controller *ctrl;
+ struct dpp_connection *conn = NULL;
+
+ wpa_printf(MSG_DEBUG, "DPP: New TCP connection (Relay)");
+
+ fd = accept(dpp->relay_sock, (struct sockaddr *) &addr, &addr_len);
+ if (fd < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to accept new connection: %s",
+ strerror(errno));
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+
+ ctrl = dpp_relay_controller_get_addr(dpp, &addr);
+ if (!ctrl && dpp->tmp_controller &&
+ dl_list_len(&dpp->tmp_controller->conn)) {
+ char txt[100];
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Remove a temporaty Controller entry for %s",
+ hostapd_ip_txt(&dpp->tmp_controller->ipaddr,
+ txt, sizeof(txt)));
+ dpp_relay_controller_free(dpp->tmp_controller);
+ dpp->tmp_controller = NULL;
+ }
+ if (!ctrl && !dpp->tmp_controller) {
+ wpa_printf(MSG_DEBUG, "DPP: Add a temporary Controller entry");
+ ctrl = os_zalloc(sizeof(*ctrl));
+ if (!ctrl)
+ goto fail;
+ dl_list_init(&ctrl->conn);
+ ctrl->global = dpp;
+ ctrl->ipaddr.af = AF_INET;
+ ctrl->ipaddr.u.v4.s_addr = addr.sin_addr.s_addr;
+ ctrl->msg_ctx = dpp->relay_msg_ctx;
+ ctrl->cb_ctx = dpp->relay_cb_ctx;
+ ctrl->tx = dpp->relay_tx;
+ ctrl->gas_resp_tx = dpp->relay_gas_resp_tx;
+ dpp->tmp_controller = ctrl;
+ }
+ if (!ctrl) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No Controller found for that address");
+ goto fail;
+ }
+
+ if (dl_list_len(&ctrl->conn) >= 15) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
+ goto fail;
+ }
+
+ conn = os_zalloc(sizeof(*conn));
+ if (!conn)
+ goto fail;
+
+ conn->global = ctrl->global;
+ conn->relay = ctrl;
+ conn->msg_ctx = ctrl->msg_ctx;
+ conn->cb_ctx = ctrl->global->cb_ctx;
+ os_memset(conn->mac_addr, 0xff, ETH_ALEN);
+ conn->sock = fd;
+
+ if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
+ dpp_controller_rx, conn, NULL) < 0)
+ goto fail;
+ conn->read_eloop = 1;
+
+ /* TODO: eloop timeout to expire connections that do not complete in
+ * reasonable time */
+ dl_list_add(&ctrl->conn, &conn->list);
+ return;
+
+fail:
+ close(fd);
+ os_free(conn);
+}
+
+
+int dpp_relay_listen(struct dpp_global *dpp, int port,
+ struct dpp_relay_config *config)
+{
+ int s;
+ int on = 1;
+ struct sockaddr_in sin;
+
+ if (dpp->relay_sock >= 0) {
+ wpa_printf(MSG_INFO, "DPP: %s(%d) - relay port already opened",
+ __func__, port);
+ return -1;
+ }
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: socket(SOCK_STREAM) failed: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: setsockopt(SO_REUSEADDR) failed: %s",
+ strerror(errno));
+ /* try to continue anyway */
+ }
+
+ if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
+ wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ /* TODO: IPv6 */
+ os_memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(port);
+ if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Failed to bind Relay TCP port: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ if (listen(s, 10 /* max backlog */) < 0 ||
+ fcntl(s, F_SETFL, O_NONBLOCK) < 0 ||
+ eloop_register_sock(s, EVENT_TYPE_READ, dpp_relay_tcp_cb, dpp,
+ NULL)) {
+ close(s);
+ return -1;
+ }
+
+ dpp->relay_sock = s;
+ dpp->relay_msg_ctx = config->msg_ctx;
+ dpp->relay_cb_ctx = config->cb_ctx;
+ dpp->relay_tx = config->tx;
+ dpp->relay_gas_resp_tx = config->gas_resp_tx;
+ wpa_printf(MSG_DEBUG, "DPP: Relay started on TCP port %d", port);
+ return 0;
+}
+
+
+void dpp_relay_stop_listen(struct dpp_global *dpp)
+{
+ if (!dpp || dpp->relay_sock < 0)
+ return;
+ eloop_unregister_sock(dpp->relay_sock, EVENT_TYPE_READ);
+ close(dpp->relay_sock);
+ dpp->relay_sock = -1;
}
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 732124f..6646301 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -384,13 +384,16 @@
u8 edmg_channel, int ht_enabled,
int vht_enabled, int he_enabled,
bool eht_enabled, int sec_channel_offset,
- int oper_chwidth, int center_segment0,
+ enum oper_chan_width oper_chwidth,
+ int center_segment0,
int center_segment1, u32 vht_caps,
struct he_capabilities *he_cap,
struct eht_capabilities *eht_cap)
{
if (!he_cap || !he_cap->he_supported)
he_enabled = 0;
+ if (!eht_cap || !eht_cap->eht_supported)
+ eht_enabled = 0;
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
@@ -402,11 +405,13 @@
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
- if (oper_chwidth == CHANWIDTH_80MHZ)
+ if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
data->bandwidth = 80;
- else if (oper_chwidth == CHANWIDTH_160MHZ ||
- oper_chwidth == CHANWIDTH_80P80MHZ)
+ else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
+ oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
data->bandwidth = 160;
+ else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ)
+ data->bandwidth = 320;
else if (sec_channel_offset)
data->bandwidth = 40;
else
@@ -482,9 +487,8 @@
return 0;
}
-#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */
if (data->eht_enabled) switch (oper_chwidth) {
- case CHANWIDTH_320MHZ:
+ case CONF_OPER_CHWIDTH_320MHZ:
if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
wpa_printf(MSG_ERROR,
@@ -492,16 +496,18 @@
return -1;
}
break;
+ default:
+ break;
}
-#endif
if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (sec_channel_offset == 0)
break;
if (mode == HOSTAPD_MODE_IEEE80211G) {
- if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ if (he_cap &&
+ !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
wpa_printf(MSG_ERROR,
"40 MHz channel width is not supported in 2.4 GHz");
@@ -510,9 +516,10 @@
break;
}
/* fall through */
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
if (mode == HOSTAPD_MODE_IEEE80211A) {
- if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ if (he_cap &&
+ !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
wpa_printf(MSG_ERROR,
"40/80 MHz channel width is not supported in 5/6 GHz");
@@ -520,35 +527,39 @@
}
}
break;
- case CHANWIDTH_80P80MHZ:
- if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ case CONF_OPER_CHWIDTH_80P80MHZ:
+ if (he_cap &&
+ !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) {
wpa_printf(MSG_ERROR,
"80+80 MHz channel width is not supported in 5/6 GHz");
return -1;
}
break;
- case CHANWIDTH_160MHZ:
- if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ case CONF_OPER_CHWIDTH_160MHZ:
+ if (he_cap &&
+ !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) {
wpa_printf(MSG_ERROR,
"160 MHz channel width is not supported in 5 / 6GHz");
return -1;
}
break;
- } else if (data->vht_enabled) switch (oper_chwidth) {
- case CHANWIDTH_USE_HT:
+ default:
break;
- case CHANWIDTH_80P80MHZ:
+ } else if (data->vht_enabled) switch (oper_chwidth) {
+ case CONF_OPER_CHWIDTH_USE_HT:
+ break;
+ case CONF_OPER_CHWIDTH_80P80MHZ:
if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
wpa_printf(MSG_ERROR,
"80+80 channel width is not supported!");
return -1;
}
/* fall through */
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
wpa_printf(MSG_ERROR,
@@ -556,11 +567,13 @@
return -1;
}
break;
+ default:
+ break;
}
if (data->eht_enabled || data->he_enabled ||
data->vht_enabled) switch (oper_chwidth) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
@@ -571,7 +584,7 @@
return -1;
}
break;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
if (center_segment1 == center_segment0 + 4 ||
center_segment1 == center_segment0 - 4) {
wpa_printf(MSG_ERROR,
@@ -580,19 +593,21 @@
}
data->center_freq2 = 5000 + center_segment1 * 5;
/* fall through */
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
data->bandwidth = 80;
if (!sec_channel_offset) {
wpa_printf(MSG_ERROR,
"80/80+80 MHz: no second channel offset");
return -1;
}
- if (oper_chwidth == CHANWIDTH_80MHZ && center_segment1) {
+ if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ &&
+ center_segment1) {
wpa_printf(MSG_ERROR,
"80 MHz: center segment 1 configured");
return -1;
}
- if (oper_chwidth == CHANWIDTH_80P80MHZ && !center_segment1) {
+ if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ &&
+ !center_segment1) {
wpa_printf(MSG_ERROR,
"80+80 MHz: center segment 1 not configured");
return -1;
@@ -631,7 +646,7 @@
}
}
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
data->bandwidth = 160;
if (center_segment1) {
wpa_printf(MSG_ERROR,
@@ -662,6 +677,43 @@
return -1;
}
break;
+ case CONF_OPER_CHWIDTH_320MHZ:
+ data->bandwidth = 320;
+ if (!data->eht_enabled || !is_6ghz_freq(freq)) {
+ wpa_printf(MSG_ERROR,
+ "320 MHz: EHT not enabled or not a 6 GHz channel");
+ return -1;
+ }
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "320 MHz: center segment 1 should not be set");
+ return -1;
+ }
+ if (center_segment0 == channel + 30 ||
+ center_segment0 == channel + 26 ||
+ center_segment0 == channel + 22 ||
+ center_segment0 == channel + 18 ||
+ center_segment0 == channel + 14 ||
+ center_segment0 == channel + 10 ||
+ center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6 ||
+ center_segment0 == channel - 10 ||
+ center_segment0 == channel - 14 ||
+ center_segment0 == channel - 18 ||
+ center_segment0 == channel - 22 ||
+ center_segment0 == channel - 26 ||
+ center_segment0 == channel - 30)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else {
+ wpa_printf(MSG_ERROR,
+ "320 MHz: wrong center segment 0");
+ return -1;
+ }
+ break;
+ default:
+ break;
}
return 0;
@@ -772,6 +824,7 @@
case 2:
case 4:
case 8:
+ case 16:
return num_chans * 20;
default:
return 20;
@@ -805,6 +858,9 @@
case 160:
bw_mask = HOSTAPD_CHAN_WIDTH_160;
break;
+ case 320:
+ bw_mask = HOSTAPD_CHAN_WIDTH_320;
+ break;
default:
bw_mask = 0;
break;
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index d87a2ca..d8ca168 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -41,7 +41,8 @@
int ht_enabled,
int vht_enabled, int he_enabled,
bool eht_enabled, int sec_channel_offset,
- int oper_chwidth, int center_segment0,
+ enum oper_chan_width oper_chwidth,
+ int center_segment0,
int center_segment1, u32 vht_caps,
struct he_capabilities *he_caps,
struct eht_capabilities *eht_cap);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 44335de..d6fd792 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -312,10 +312,14 @@
elems->pasn_params_len = elen;
break;
case WLAN_EID_EXT_EHT_CAPABILITIES:
+ if (elen < EHT_CAPABILITIES_IE_MIN_LEN)
+ break;
elems->eht_capabilities = pos;
elems->eht_capabilities_len = elen;
break;
case WLAN_EID_EXT_EHT_OPERATION:
+ if (elen < EHT_OPERATION_IE_MIN_LEN)
+ break;
elems->eht_operation = pos;
elems->eht_operation_len = elen;
break;
@@ -886,7 +890,7 @@
{
u8 op_class;
- return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT,
+ return ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_USE_HT,
&op_class, channel);
}
@@ -896,15 +900,15 @@
* for HT40, VHT, and HE. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
- * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
+ * @chanwidth: VHT/EDMG/etc. channel width
* @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
*/
-enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
- int sec_channel,
- int chanwidth,
- u8 *op_class, u8 *channel)
+enum hostapd_hw_mode
+ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
+ enum oper_chan_width chanwidth,
+ u8 *op_class, u8 *channel)
{
u8 vht_opclass;
@@ -952,13 +956,13 @@
}
switch (chanwidth) {
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
vht_opclass = 128;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
vht_opclass = 129;
break;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
vht_opclass = 130;
break;
default:
@@ -1057,15 +1061,18 @@
return NUM_HOSTAPD_MODES;
switch (chanwidth) {
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
*op_class = 133;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
*op_class = 134;
break;
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
*op_class = 135;
break;
+ case CONF_OPER_CHWIDTH_320MHZ:
+ *op_class = 137;
+ break;
default:
if (sec_channel)
*op_class = 132;
@@ -1090,12 +1097,12 @@
return NUM_HOSTAPD_MODES;
switch (chanwidth) {
- case CHANWIDTH_USE_HT:
- case CHANWIDTH_2160MHZ:
+ case CONF_OPER_CHWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_2160MHZ:
*channel = (freq - 56160) / 2160;
*op_class = 180;
break;
- case CHANWIDTH_4320MHZ:
+ case CONF_OPER_CHWIDTH_4320MHZ:
/* EDMG channels 9 - 13 */
if (freq > 56160 + 2160 * 5)
return NUM_HOSTAPD_MODES;
@@ -1103,7 +1110,7 @@
*channel = (freq - 56160) / 2160 + 8;
*op_class = 181;
break;
- case CHANWIDTH_6480MHZ:
+ case CONF_OPER_CHWIDTH_6480MHZ:
/* EDMG channels 17 - 20 */
if (freq > 56160 + 2160 * 4)
return NUM_HOSTAPD_MODES;
@@ -1111,7 +1118,7 @@
*channel = (freq - 56160) / 2160 + 16;
*op_class = 182;
break;
- case CHANWIDTH_8640MHZ:
+ case CONF_OPER_CHWIDTH_8640MHZ:
/* EDMG channels 25 - 27 */
if (freq > 56160 + 2160 * 3)
return NUM_HOSTAPD_MODES;
@@ -1140,28 +1147,31 @@
case CHAN_WIDTH_20_NOHT:
case CHAN_WIDTH_20:
case CHAN_WIDTH_40:
- cw = CHANWIDTH_USE_HT;
+ cw = CONF_OPER_CHWIDTH_USE_HT;
break;
case CHAN_WIDTH_80:
- cw = CHANWIDTH_80MHZ;
+ cw = CONF_OPER_CHWIDTH_80MHZ;
break;
case CHAN_WIDTH_80P80:
- cw = CHANWIDTH_80P80MHZ;
+ cw = CONF_OPER_CHWIDTH_80P80MHZ;
break;
case CHAN_WIDTH_160:
- cw = CHANWIDTH_160MHZ;
+ cw = CONF_OPER_CHWIDTH_160MHZ;
break;
case CHAN_WIDTH_2160:
- cw = CHANWIDTH_2160MHZ;
+ cw = CONF_OPER_CHWIDTH_2160MHZ;
break;
case CHAN_WIDTH_4320:
- cw = CHANWIDTH_4320MHZ;
+ cw = CONF_OPER_CHWIDTH_4320MHZ;
break;
case CHAN_WIDTH_6480:
- cw = CHANWIDTH_6480MHZ;
+ cw = CONF_OPER_CHWIDTH_6480MHZ;
break;
case CHAN_WIDTH_8640:
- cw = CHANWIDTH_8640MHZ;
+ cw = CONF_OPER_CHWIDTH_8640MHZ;
+ break;
+ case CHAN_WIDTH_320:
+ cw = CONF_OPER_CHWIDTH_320MHZ;
break;
}
@@ -1458,6 +1468,7 @@
case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
if (chan < 1 || chan > 233)
return -1;
return 5950 + chan * 5;
@@ -2272,6 +2283,9 @@
/* channels 15, 47, 79...*/
if ((idx & 0x1f) == 0xf)
return 3; /* 160 MHz */
+ /* channels 31, 63, 95, 127, 159, 191 */
+ if ((idx & 0x1f) == 0x1f && idx < 192)
+ return 4; /* 320 MHz */
return -1;
}
@@ -2294,7 +2308,7 @@
bool is_6ghz_op_class(u8 op_class)
{
- return op_class >= 131 && op_class <= 136;
+ return op_class >= 131 && op_class <= 137;
}
@@ -2600,6 +2614,8 @@
return 160;
case 136: /* UHB channels, 20 MHz: 2 */
return 20;
+ case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
+ return 320;
case 180: /* 60 GHz band, channels 1..8 */
return 2160;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
@@ -2614,64 +2630,66 @@
}
-int op_class_to_ch_width(u8 op_class)
+enum oper_chan_width op_class_to_ch_width(u8 op_class)
{
switch (op_class) {
case 81:
case 82:
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 83: /* channels 1..9; 40 MHz */
case 84: /* channels 5..13; 40 MHz */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 115: /* channels 36,40,44,48; indoor only */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 116: /* channels 36,44; 40 MHz; indoor only */
case 117: /* channels 40,48; 40 MHz; indoor only */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 118: /* channels 52,56,60,64; dfs */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 119: /* channels 52,60; 40 MHz; dfs */
case 120: /* channels 56,64; 40 MHz; dfs */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 121: /* channels 100-140 */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 122: /* channels 100-142; 40 MHz */
case 123: /* channels 104-136; 40 MHz */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 124: /* channels 149,153,157,161 */
case 125: /* channels 149,153,157,161,165,169,171 */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 126: /* channels 149,157,165, 173; 40 MHz */
case 127: /* channels 153,161,169,177; 40 MHz */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
- return CHANWIDTH_80MHZ;
+ return CONF_OPER_CHWIDTH_80MHZ;
case 129: /* center freqs 50, 114, 163; 160 MHz */
- return CHANWIDTH_160MHZ;
+ return CONF_OPER_CHWIDTH_160MHZ;
case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
- return CHANWIDTH_80P80MHZ;
+ return CONF_OPER_CHWIDTH_80P80MHZ;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
- return CHANWIDTH_80MHZ;
+ return CONF_OPER_CHWIDTH_80MHZ;
case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
- return CHANWIDTH_160MHZ;
+ return CONF_OPER_CHWIDTH_160MHZ;
case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
- return CHANWIDTH_80P80MHZ;
+ return CONF_OPER_CHWIDTH_80P80MHZ;
case 136: /* UHB channels, 20 MHz: 2 */
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
+ case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */
+ return CONF_OPER_CHWIDTH_320MHZ;
case 180: /* 60 GHz band, channels 1..8 */
- return CHANWIDTH_2160MHZ;
+ return CONF_OPER_CHWIDTH_2160MHZ;
case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */
- return CHANWIDTH_4320MHZ;
+ return CONF_OPER_CHWIDTH_4320MHZ;
case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */
- return CHANWIDTH_6480MHZ;
+ return CONF_OPER_CHWIDTH_6480MHZ;
case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */
- return CHANWIDTH_8640MHZ;
+ return CONF_OPER_CHWIDTH_8640MHZ;
}
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
}
struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems,
@@ -2837,6 +2855,7 @@
struct supported_chan_width supported_width;
supported_width.is_160_supported = 0;
supported_width.is_80p80_supported = 0;
+ supported_width.is_320_supported = 0;
if (elems == NULL)
return supported_width;
@@ -2844,6 +2863,8 @@
(struct ieee80211_vht_capabilities *) elems->vht_capabilities;
struct ieee80211_he_capabilities *hecaps =
(struct ieee80211_he_capabilities *) elems->he_capabilities;
+ struct ieee80211_eht_capabilities *ehtcaps =
+ (struct ieee80211_eht_capabilities *) elems->eht_capabilities;
if (vhtcaps) {
le32 vht_capabilities_info =
@@ -2861,8 +2882,16 @@
if (channel_width_set & HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
supported_width.is_80p80_supported = 1;
}
- wpa_printf(MSG_DEBUG, " IE indicate 160 supported: %u, 80+80 supported: %u",
- supported_width.is_160_supported, supported_width.is_80p80_supported);
+ if (ehtcaps) {
+ if (ehtcaps->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+ supported_width.is_320_supported = 1;
+ }
+ wpa_printf(MSG_DEBUG,
+ " IE indicates 320 supported: %u, 160 supported: %u, 80+80 supported: %u",
+ supported_width.is_320_supported,
+ supported_width.is_160_supported,
+ supported_width.is_80p80_supported);
return supported_width;
}
@@ -2972,6 +3001,39 @@
return channel_width;
}
+/* Parse EHT operation IE to get EHT operation channel width */
+static enum chan_width get_eht_operation_channel_width(
+ struct ieee80211_eht_operation *eht_oper,
+ int eht_oper_len)
+{
+ enum chan_width channel_width = CHAN_WIDTH_UNKNOWN;
+ if (!(eht_oper->oper_params & EHT_OPER_INFO_PRESENT) ||
+ eht_oper_len < (EHT_OPERATION_IE_MIN_LEN + EHT_OPER_INFO_MIN_LEN))
+ return channel_width;
+
+ switch (eht_oper->oper_info.control & EHT_OPER_CHANNEL_WIDTH_MASK) {
+ case EHT_OPER_CHANNEL_WIDTH_20MHZ:
+ channel_width = CHAN_WIDTH_20;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_40MHZ:
+ channel_width = CHAN_WIDTH_40;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_80MHZ:
+ channel_width = CHAN_WIDTH_80;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_160MHZ:
+ channel_width = CHAN_WIDTH_160;
+ break;
+ case EHT_OPER_CHANNEL_WIDTH_320MHZ:
+ channel_width = CHAN_WIDTH_320;
+ break;
+ default:
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " EHT operation CBW: %u", channel_width);
+ return channel_width;
+}
+
/* Parse HT/VHT/HE operation IEs to get operation channel width */
enum chan_width get_operation_channel_width(struct ieee802_11_elems *elems)
{
@@ -2985,7 +3047,14 @@
(struct ieee80211_vht_operation_info *) elems->vht_operation;
struct ieee80211_he_operation *he_oper =
(struct ieee80211_he_operation *) elems->he_operation;
- if (he_oper)
+ struct ieee80211_eht_operation *eht_oper =
+ (struct ieee80211_eht_operation *) elems->eht_operation;
+
+ if (eht_oper)
+ channel_width = get_eht_operation_channel_width(
+ eht_oper, elems->eht_operation_len);
+
+ if (channel_width == CHAN_WIDTH_UNKNOWN && he_oper)
channel_width = get_he_operation_channel_width(
he_oper, elems->he_operation_len);
@@ -3009,7 +3078,11 @@
enum chan_width ap_operation_chan_width,
struct supported_chan_width sta_supported_chan_width)
{
- if (ap_operation_chan_width == CHAN_WIDTH_160)
+ if (ap_operation_chan_width == CHAN_WIDTH_320 &&
+ sta_supported_chan_width.is_320_supported)
+ return CHAN_WIDTH_320;
+ if (ap_operation_chan_width == CHAN_WIDTH_160 ||
+ ap_operation_chan_width == CHAN_WIDTH_320)
return (sta_supported_chan_width.is_160_supported)
? CHAN_WIDTH_160 : CHAN_WIDTH_80;
if (ap_operation_chan_width == CHAN_WIDTH_80P80)
@@ -3017,3 +3090,38 @@
? CHAN_WIDTH_80P80 : CHAN_WIDTH_80;
return ap_operation_chan_width;
}
+
+const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type)
+{
+ const struct element *elem;
+
+ if (!ies)
+ return NULL;
+
+ for_each_element_extid(elem, WLAN_EID_EXT_MULTI_LINK, ies, len) {
+ if (elem->datalen >= 2 &&
+ (elem->data[1] & MULTI_LINK_CONTROL_TYPE_MASK) == type)
+ return &elem->id;
+ }
+
+ return NULL;
+}
+
+
+const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len)
+{
+ const size_t mld_addr_pos =
+ 2 /* Control field */ +
+ 1 /* Common Info Length field */;
+ const size_t fixed_len = mld_addr_pos +
+ ETH_ALEN /* MLD MAC Address field */;
+
+ if (len < fixed_len)
+ return NULL;
+
+ if ((buf[0] & MULTI_LINK_CONTROL_TYPE_MASK) !=
+ MULTI_LINK_CONTROL_TYPE_BASIC)
+ return NULL;
+
+ return &buf[mld_addr_pos];
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index e21f7be..ff31e8d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -215,9 +215,10 @@
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
-enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
- int sec_channel, int vht,
- u8 *op_class, u8 *channel);
+enum hostapd_hw_mode
+ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel,
+ enum oper_chan_width chanwidth,
+ u8 *op_class, u8 *channel);
int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
int sec_channel, u8 *op_class, u8 *channel);
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
@@ -279,7 +280,7 @@
unsigned int capab);
bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab);
int op_class_to_bandwidth(u8 op_class);
-int op_class_to_ch_width(u8 op_class);
+enum oper_chan_width op_class_to_ch_width(u8 op_class);
/* element iteration helpers */
#define for_each_element(_elem, _data, _datalen) \
@@ -342,12 +343,15 @@
const u8 *data, u8 len);
struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems,
u8 eid, u8 eid_ext);
+const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type);
+const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len);
int get_max_nss_capability(struct ieee802_11_elems *elems, int parse_for_rx);
struct supported_chan_width {
u8 is_160_supported;
u8 is_80p80_supported;
+ u8 is_320_supported;
};
struct supported_chan_width get_supported_channel_width(struct ieee802_11_elems *elems);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index c341a1d..ec3b42b 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -495,6 +495,7 @@
#define WLAN_EID_EXT_EHT_CAPABILITIES 108
#define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109
#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
+#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -610,12 +611,20 @@
#define WLAN_ACTION_ROBUST_AV_STREAMING 19
#define WLAN_ACTION_UNPROTECTED_DMG 20
#define WLAN_ACTION_VHT 21
-#define WLAN_ACTION_S1G 22
-#define WLAN_ACTION_S1G_RELAY 23
+#define WLAN_ACTION_UNPROTECTED_S1G 22
+#define WLAN_ACTION_S1G 23
#define WLAN_ACTION_FLOW_CONTROL 24
#define WLAN_ACTION_CTRL_RESP_MCS_NEG 25
#define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_CDMG 27
+#define WLAN_ACTION_CMMG 28
+#define WLAN_ACTION_GLK 29
+#define WLAN_ACTION_HE 30
+#define WLAN_ACTION_PROTECTED_HE 31
+#define WLAN_ACTION_WUR 32
#define WLAN_ACTION_PROTECTED_FTM 34
+#define WLAN_ACTION_EHT 36
+#define WLAN_ACTION_PROTECTED_EHT 37
#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Note: 128-255 used to report errors by setting category | 0x80 */
@@ -1340,16 +1349,11 @@
#define VHT_RX_NSS_MAX_STREAMS 8
-/* VHT/EDMG channel widths */
+/* VHT operation information - channel widths */
#define CHANWIDTH_USE_HT 0
#define CHANWIDTH_80MHZ 1
#define CHANWIDTH_160MHZ 2
#define CHANWIDTH_80P80MHZ 3
-#define CHANWIDTH_2160MHZ 4
-#define CHANWIDTH_4320MHZ 5
-#define CHANWIDTH_6480MHZ 6
-#define CHANWIDTH_8640MHZ 7
-#define CHANWIDTH_40MHZ_6GHZ 8
#define HE_NSS_MAX_STREAMS 8
@@ -2442,11 +2446,14 @@
/* IEEE P802.11be/D1.5, 9.4.2.311 - EHT Operation element */
+#define EHT_OPERATION_IE_MIN_LEN 1
+
/* Figure 9-1002b: EHT Operation Parameters field subfields */
#define EHT_OPER_INFO_PRESENT BIT(0)
#define EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
/* Control subfield: Channel Width subfield; see Table 9-401b */
+#define EHT_OPER_CHANNEL_WIDTH_MASK 0x7
#define EHT_OPER_CHANNEL_WIDTH_20MHZ 0
#define EHT_OPER_CHANNEL_WIDTH_40MHZ 1
#define EHT_OPER_CHANNEL_WIDTH_80MHZ 2
@@ -2454,6 +2461,8 @@
#define EHT_OPER_CHANNEL_WIDTH_320MHZ 4
/* Figure 9-1002c: EHT Operation Information field format */
+#define EHT_OPER_INFO_MIN_LEN 3
+
struct ieee80211_eht_oper_info {
u8 control; /* B0..B2: Channel Width */
u8 ccfs0;
@@ -2469,6 +2478,8 @@
/* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */
+#define EHT_CAPABILITIES_IE_MIN_LEN 11
+
/* Figure 9-1002af: EHT MAC Capabilities Information field */
#define EHT_MACCAP_EPCS_PRIO BIT(0)
#define EHT_MACCAP_OM_CONTROL BIT(1)
@@ -2539,6 +2550,27 @@
u8 optional[EHT_MCS_NSS_CAPAB_LEN + EHT_PPE_THRESH_CAPAB_LEN];
} STRUCT_PACKED;
+/* IEEE P802.11be/D2.1, 9.4.2.312 - Multi-Link element */
+
+/* Figure 9-1002f: Multi-Link Control field */
+#define MULTI_LINK_CONTROL_TYPE_MASK 0x07
+
+/* Table 9-401c: Mult-Link element Type subfield encoding */
+#define MULTI_LINK_CONTROL_TYPE_BASIC 0
+#define MULTI_LINK_CONTROL_TYPE_PROBE_REQ 1
+#define MULTI_LINK_CONTROL_TYPE_RECONF 2
+#define MULTI_LINK_CONTROL_TYPE_TDLS 3
+#define MULTI_LINK_CONTROL_TYPE_PRIOR_ACCESS 4
+
+/* Figure 9-1002g: Presence Bitmap subfield of the Basic Multi-Link element */
+#define BASIC_MULTI_LINK_CTRL0_PRES_LINK_ID 0x10
+#define BASIC_MULTI_LINK_CTRL0_PRES_BSS_PARAM_CH_COUNT 0x20
+#define BASIC_MULTI_LINK_CTRL0_PRES_MSD_INFO 0x40
+#define BASIC_MULTI_LINK_CTRL0_PRES_EML_CAPA 0x80
+
+#define BASIC_MULTI_LINK_CTRL1_PRES_MLD_CAPA 0x01
+#define BASIC_MULTI_LINK_CTRL1_PRES_AP_MLD_ID 0x02
+
/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
diff --git a/src/common/ocv.c b/src/common/ocv.c
index c9dc14f..d77bc4b 100644
--- a/src/common/ocv.c
+++ b/src/common/ocv.c
@@ -159,11 +159,10 @@
}
/*
- * When using a 160 or 80+80 MHz channel to transmit, verify that we use
+ * When using an 80+80 MHz channel to transmit, verify that we use
* the same segments as the receiver by comparing frequency segment 1.
*/
- if ((ci->chanwidth == CHAN_WIDTH_160 ||
- ci->chanwidth == CHAN_WIDTH_80P80) &&
+ if (ci->chanwidth == CHAN_WIDTH_80P80 &&
tx_seg1_idx != oci.seg1_idx) {
os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
"frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
diff --git a/src/common/ptksa_cache.c b/src/common/ptksa_cache.c
index 8fcb135..aacc425 100644
--- a/src/common/ptksa_cache.c
+++ b/src/common/ptksa_cache.c
@@ -51,7 +51,10 @@
wpa_printf(MSG_DEBUG, "Expired PTKSA cache entry for " MACSTR,
MAC2STR(e->addr));
- ptksa_cache_free_entry(ptksa, e);
+ if (e->cb && e->ctx)
+ e->cb(e);
+ else
+ ptksa_cache_free_entry(ptksa, e);
}
ptksa_cache_set_expiration(ptksa);
@@ -254,10 +257,13 @@
/*
* ptksa_cache_add - Add a PTKSA cache entry
* @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @own_addr: Own MAC address
* @addr: Peer address
* @cipher: The cipher used
* @life_time: The PTK life time in seconds
* @ptk: The PTK
+ * @life_time_expiry_cb: Callback for alternative expiration handling
+ * @ctx: Context pointer to save into e->ctx for the callback
* Returns: Pointer to the added PTKSA cache entry or %NULL on error
*
* This function creates a PTKSA entry and adds it to the PTKSA cache.
@@ -265,12 +271,17 @@
* this entry will be replaced with the new entry.
*/
struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *own_addr,
const u8 *addr, u32 cipher,
u32 life_time,
- const struct wpa_ptk *ptk)
+ const struct wpa_ptk *ptk,
+ void (*life_time_expiry_cb)
+ (struct ptksa_cache_entry *e),
+ void *ctx)
{
struct ptksa_cache_entry *entry, *tmp, *tmp2 = NULL;
struct os_reltime now;
+ bool set_expiry = false;
if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE)
return NULL;
@@ -289,6 +300,11 @@
dl_list_init(&entry->list);
os_memcpy(entry->addr, addr, ETH_ALEN);
entry->cipher = cipher;
+ entry->cb = life_time_expiry_cb;
+ entry->ctx = ctx;
+
+ if (own_addr)
+ os_memcpy(entry->own_addr, own_addr, ETH_ALEN);
os_memcpy(&entry->ptk, ptk, sizeof(entry->ptk));
@@ -302,6 +318,8 @@
}
}
+ if (dl_list_empty(&entry->list))
+ set_expiry = true;
/*
* If the expiration is later then all other or the list is empty
* entries, add it to the end of the list;
@@ -317,5 +335,8 @@
"Added PTKSA cache entry addr=" MACSTR " cipher=%u",
MAC2STR(addr), cipher);
+ if (set_expiry)
+ ptksa_cache_set_expiration(ptksa);
+
return entry;
}
diff --git a/src/common/ptksa_cache.h b/src/common/ptksa_cache.h
index 28ef291..a643a26 100644
--- a/src/common/ptksa_cache.h
+++ b/src/common/ptksa_cache.h
@@ -23,6 +23,9 @@
os_time_t expiration;
u32 cipher;
u8 addr[ETH_ALEN];
+ u8 own_addr[ETH_ALEN];
+ void (*cb)(struct ptksa_cache_entry *e);
+ void *ctx;
};
#ifdef CONFIG_PTKSA_CACHE
@@ -35,9 +38,13 @@
const u8 *addr, u32 cipher);
int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len);
struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *own_addr,
const u8 *addr, u32 cipher,
u32 life_time,
- const struct wpa_ptk *ptk);
+ const struct wpa_ptk *ptk,
+ void (*cb)
+ (struct ptksa_cache_entry *e),
+ void *ctx);
void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher);
#else /* CONFIG_PTKSA_CACHE */
@@ -64,8 +71,9 @@
}
static inline struct ptksa_cache_entry *
-ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher,
- u32 life_time, const struct wpa_ptk *ptk)
+ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *own_addr, const u8 *addr,
+ u32 cipher, u32 life_time, const struct wpa_ptk *ptk,
+ void (*cb)(struct ptksa_cache_entry *e), void *ctx)
{
return NULL;
}
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index d04c8d1..215ba91 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -2,6 +2,7 @@
* Qualcomm Atheros OUI and vendor specific assignments
* Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
* Copyright (c) 2018-2020, The Linux Foundation
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -711,10 +712,10 @@
* This event contains Tx VDEV group information, other VDEVs
* interface index, and status information.
*
- * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY: Vendor command to
- * configure the concurrent session policies when multiple STA interfaces
+ * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY: Vendor command to
+ * configure the concurrent session policies when multiple interfaces
* are (getting) active. The attributes used by this command are defined
- * in enum qca_wlan_vendor_attr_concurrent_sta_policy.
+ * in enum qca_wlan_vendor_attr_concurrent_policy.
*
* @QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS: Userspace can use this command
* to query usable channels for different interface types such as STA,
@@ -788,6 +789,69 @@
*
* The attributes used with this command are defined in
* enum qca_wlan_vendor_attr_mcc_quota.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX: Vendor command to
+ * get the WLAN radio combinations matrix supported by the device which
+ * provides the device simultaneous radio configurations such as
+ * standalone, dual band simultaneous, and single band simultaneous.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_radio_combination_matrix.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY: Event indicating to the user space
+ * that the driver is ready for operations again after recovering from
+ * internal failures. This occurs following a failure that was indicated by
+ * @QCA_NL80211_VENDOR_SUBCMD_HANG.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PASN: Subcommand used to offload preassociation
+ * security negotiation and key generation to user space.
+ *
+ * When used as an event, the driver requests userspace to trigger the PASN
+ * authentication or dropping of a PTKSA for the indicated peer devices.
+ * When used as a command response, userspace indicates a consolidated
+ * status report for all the peers that were requested for.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_pasn.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT: Subcommand used to set
+ * secure ranging context such as TK and LTF keyseed for each peer
+ * requested by the driver with a @QCA_NL80211_VENDOR_SUBCMD_PASN event.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_secure_ranging_ctx.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD: This vendor subcommand is used to
+ * enable/disable offload processing in firmware during system/runtime
+ * suspend for CoAP messages (see RFC7252: The Constrained Application
+ * Protocol) and fetch information of the CoAP messages cached during
+ * offload processing.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_coap_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG: Subcommand to configure
+ * (add, remove, or change) a Stream Classification Service (SCS) rule.
+ *
+ * The attributes used with this event are defined in
+ * enum qca_wlan_vendor_attr_scs_rule_config.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY: Fetch SAR capabilities
+ * supported by the WLAN firmware.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_sar_capability.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SR: Subcommand used to implement Spatial Reuse
+ * (SR) feature. This command is used by userspace to configure SR
+ * parameters to the driver and to get the SR related parameters and
+ * statistics with synchronous responses from the driver.
+ * The driver also uses this command to send asynchronous events to
+ * userspace to indicate suspend/resume of SR feature and changes
+ * in SR parameters.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_sr.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -974,7 +1038,7 @@
QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID = 194,
QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS = 195,
QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS = 196,
- QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY = 197,
+ QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY = 197,
QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS = 198,
QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY = 199,
QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD = 200,
@@ -983,8 +1047,23 @@
QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS = 203,
QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG = 204,
QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA = 205,
+ /* 206..212 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX = 213,
+ QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY = 214,
+ QCA_NL80211_VENDOR_SUBCMD_PASN = 215,
+ QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT = 216,
+ QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD = 217,
+ QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG = 218,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY = 219,
+ QCA_NL80211_VENDOR_SUBCMD_SR = 220,
};
+/* Compatibility defines for previously used subcmd names.
+ * These values should not be used in any new implementation.
+ */
+#define QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY \
+ QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY
+
enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_INVALID = 0,
/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
@@ -1270,6 +1349,9 @@
enum qca_wlan_vendor_attr_roam_auth {
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
+ /* Indicates BSSID of the roamed AP for non-MLO roaming and MLD address
+ * of the roamed AP for MLO roaming.
+ */
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
@@ -1314,6 +1396,11 @@
* Defined by enum qca_roam_reason.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON = 14,
+ /* A nested attribute containing per-link information of all the links
+ * of MLO connection done while roaming. The attributes used inside this
+ * nested attribute are defined in enum qca_wlan_vendor_attr_mlo_links.
+ */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS = 15,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
@@ -1495,6 +1582,12 @@
* Used with command to configure ACS operation for EHT mode.
* Disable (flag attribute not present) - EHT disabled and
* Enable (flag attribute present) - EHT enabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME: Optional (u32).
+ * Used with command to configure how older scan can be considered for ACS
+ * scoring. In case scan was performed on a partial set of channels configured
+ * with this command within last QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME
+ * (in ms), scan only the remaining channels.
*/
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
@@ -1517,6 +1610,7 @@
QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP = 18,
QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED = 19,
+ QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME = 20,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
@@ -1600,17 +1694,41 @@
* operation is specifically mentioned (against its respective
* documentation) to support either of these or both modes.
* @QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI: Flag indicates
- * that the driver requires add/del virtual interface path using the
+ * that the driver requires add/del virtual interface path using the
* generic nl80211 commands for NDP interface create/delete and to
* register/unregister the netdev instead of creating/deleting the NDP
* interface using the vendor commands
* QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE and
* QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE. With the latest kernel
- * (5.12 version onward), interface creation/deletion is not allowed using
- * vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK
- * during the register/unregister of netdev. Create and delete NDP
- * interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE
- * commands respectively if the driver advertises this capability set.
+ * (5.12 version onward), interface creation/deletion is not allowed using
+ * vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK
+ * during the register/unregister of netdev. Create and delete NDP
+ * interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE
+ * commands respectively if the driver advertises this capability set.
+ * @QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA: Flag indicates that the device in
+ * station mode supports secure LTF. If NL80211_EXT_FEATURE_SECURE_LTF is
+ * set, then QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA will be ignored.
+ * @QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP: Flag indicates that the device in AP
+ * mode supports secure LTF. If NL80211_EXT_FEATURE_SECURE_LTF is set, then
+ * QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP will be ignored.
+ * @QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA: Flag indicates that the device in
+ * station mode supports secure RTT measurement exchange. If
+ * NL80211_EXT_FEATURE_SECURE_RTT is set,
+ * QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA will be ignored.
+ * @QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP: Flag indicates that the device in AP
+ * mode supports secure RTT measurement exchange. If
+ * NL80211_EXT_FEATURE_SECURE_RTT is set,
+ * QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP will be ignored.
+ * @QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA: Flag indicates that
+ * the device in station mode supports protection of range negotiation and
+ * measurement management frames. If
+ * NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE is set, then
+ * QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA will be ignored.
+ * @QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP: Flag indicates that
+ * the device in AP mode supports protection of range negotiation and
+ * measurement management frames. If
+ * NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE is set, then
+ * QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP will be ignored.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1622,7 +1740,7 @@
QCA_WLAN_VENDOR_FEATURE_OCE_AP = 5,
QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6,
QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7,
- QCA_WLAN_VENDOR_FEATURE_TWT = 8,
+ QCA_WLAN_VENDOR_FEATURE_TWT = 8,
QCA_WLAN_VENDOR_FEATURE_11AX = 9,
QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10,
QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11,
@@ -1630,6 +1748,12 @@
QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13,
QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14,
QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI = 15,
+ QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA = 16,
+ QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP = 17,
+ QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA = 18,
+ QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP = 19,
+ QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA = 20,
+ QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP = 21,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -2643,6 +2767,20 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD = 81,
+ /*
+ * 8-bit unsigned value. This attribute can be used to configure the
+ * data path mode to be followed for audio traffic. Possible values
+ * are defined in enum qca_wlan_audio_data_path.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AUDIO_DATA_PATH = 82,
+
+ /*
+ * 8-bit unsigned value. This attribute can be used to configure the
+ * Dedicated Bluetooth Antenna Mode (DBAM) feature. Possible values for
+ * this attribute are defined in the enum qca_wlan_dbam_config.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DBAM = 83,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -2658,6 +2796,19 @@
QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL
/**
+ * enum qca_dbam_config - Specifies DBAM config mode
+ * @QCA_DBAM_DISABLE: Firmware disables DBAM
+ * @QCA_DBAM_ENABLE: Firmware enables DBAM opportunistically when
+ * internal criteria are met.
+ * @QCA_DBAM_FORCE_ENABLE: Firmware enables DBAM forcefully.
+ */
+enum qca_dbam_config {
+ QCA_DBAM_DISABLE = 0,
+ QCA_DBAM_ENABLE = 1,
+ QCA_DBAM_FORCE_ENABLE = 2,
+};
+
+/**
* enum qca_wlan_ani_setting - ANI setting type
* @QCA_WLAN_ANI_SETTING_AUTO: Automatically determine ANI level
* @QCA_WLAN_ANI_SETTING_FIXED: Fix ANI level to the dBm parameter
@@ -4070,6 +4221,22 @@
* Possible values are 0-100.
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE = 87,
+ /* Unsigned 32 bit value. The number of Beacon frames which are received
+ * from the associated AP and indicate buffered unicast frame(s) for us
+ * in the TIM element.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON = 88,
+ /* Unsigned 32 bit value. The total number of Beacon frames received
+ * from the associated AP that have wrongly indicated buffered unicast
+ * traffic in the TIM element for us.
+ * Below scenarios will be considered as wrong TIM element beacon:
+ * 1) The related TIM element is set in the beacon for STA but STA
+ * doesn’t receive any unicast data after this beacon.
+ * 2) The related TIM element is still set in the beacon for STA
+ * after STA has indicated power save exit by QoS Null Data frame.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR = 89,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -4683,7 +4850,7 @@
/**
* enum qca_vendor_attr_roam_control - Attributes to carry roam configuration
- * The following attributes are used to set/get/clear the respective
+ * The following attributes are used to set/get/clear the respective
* configurations to/from the driver.
* For the get, the attribute for the configuration to be queried shall
* carry any of its acceptable values to the driver. In return, the driver
@@ -4885,6 +5052,12 @@
* Optional parameter. Scan dwell time for 6G Non Preferred Scanning
* Channels. If this attribute is not configured, the driver shall proceed
* with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_RX_LINKSPEED_THRESHOLD: u16 value in Mbps.
+ * Optional parameter. RX link speed threshold to disable roaming.
+ * If the current RX link speed is above the threshold, roaming is not
+ * needed. If this attribute is not configured, or if it is set to 0, the
+ * driver will not consider the RX link speed in the roaming decision.
*/
enum qca_vendor_attr_roam_control {
QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
@@ -4910,6 +5083,7 @@
QCA_ATTR_ROAM_CONTROL_MAXIMUM_AWAY_TIME = 21,
QCA_ATTR_ROAM_CONTROL_SCAN_6G_PSC_DWELL_TIME = 22,
QCA_ATTR_ROAM_CONTROL_SCAN_6G_NON_PSC_DWELL_TIME = 23,
+ QCA_ATTR_ROAM_CONTROL_LINKSPEED_THRESHOLD = 24,
/* keep last */
QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
@@ -5727,7 +5901,7 @@
/* HE 40 with extension channel below */
QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40MINUS = 1 << 30,
/* HE 40 intolerant */
- QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40INTOL = 1 << 31,
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40INTOL = 1U << 31,
};
/**
@@ -8647,6 +8821,16 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE = 58,
+ /* 8-bit unsigned value to configure the driver to enable/disable the
+ * periodic sounding for Tx beamformer functionality. The default
+ * behavior uses algorithm to do sounding based on packet stats.
+ *
+ * 0 - Default behavior.
+ * 1 - Enable the periodic sounding for Tx beamformer.
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BEAMFORMER_PERIODIC_SOUNDING = 59,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -9359,6 +9543,14 @@
* @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF: Optional (u64)
* This field contains absolute TSF value of the time at which the TWT
* session will be resumed.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET: Optional (s32)
+ * This field will be used when device supports Flexible TWT.
+ * This field contains an offset value by which to shift the starting time
+ * of the next service period. The value of offset can be negative or positive.
+ * If provided, this attribute will override
+ * QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME. The units are in microseconds.
+ *
*/
enum qca_wlan_vendor_attr_twt_nudge {
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_INVALID = 0,
@@ -9367,6 +9559,7 @@
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE = 3,
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR = 4,
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET = 6,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST,
@@ -10657,14 +10850,21 @@
* These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of
* %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
*
- * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared.
- * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated.
+ * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4 GHz are shared.
+ * @QCA_BTC_CHAIN_SEPARATED_HYBRID: chains of BT and WLAN 2.4 GHz are
+ * separated, hybrid mode.
+ * @QCA_BTC_CHAIN_SEPARATED_FDD: chains of BT and WLAN 2.4 GHz are
+ * separated, fixed FDD mode.
*/
enum qca_btc_chain_mode {
QCA_BTC_CHAIN_SHARED = 0,
- QCA_BTC_CHAIN_SEPARATED = 1,
+ QCA_BTC_CHAIN_SEPARATED_HYBRID = 1,
+ QCA_BTC_CHAIN_SEPARATED_FDD = 2,
};
+/* deprecated legacy name */
+#define QCA_BTC_CHAIN_SEPARATED QCA_BTC_CHAIN_SEPARATED_HYBRID
+
/**
* enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex
* chain mode.
@@ -11001,6 +11201,18 @@
* This represents the average congestion duration of uplink frames in MAC
* queue in unit of ms. This can be queried either in connected state or
* disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS: Array of u32 nested
+ * values, used in AP mode. This represents the MPDU packet count per MCS
+ * rate value of TX packets. Every index of this nested attribute corresponds
+ * to MCS index, e.g., Index 0 represents MCS0 TX rate. This can be
+ * queried in connected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_RX_PACKETS: Array of u32 nested
+ * values, used in AP mode. This represents the MPDU packet count per MCS
+ * rate value of RX packets. Every index of this nested attribute corresponds
+ * to MCS index, e.g., Index 0 represents MCS0 RX rate. This can be
+ * queried in connected state.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -11054,6 +11266,8 @@
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON = 48,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON = 49,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY = 50,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS = 51,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_RX_PACKETS = 52,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -11573,24 +11787,58 @@
};
/**
- * enum qca_wlan_vendor_attr_concurrent_sta_policy - Defines attributes
- * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY vendor command.
+ * enum qca_wlan_concurrent_ap_policy_config - Concurrent AP policies
*
- * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG:
+ * @QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED: No specific policy for this AP
+ * interface.
+ *
+ * @QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO: Select interface concurrencies
+ * to meet gaming audio latency requirements.
+ *
+ * @QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: Select interface
+ * concurrencies to meet lossless audio streaming requirements.
+ */
+enum qca_wlan_concurrent_ap_policy_config {
+ QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED = 0,
+ QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO = 1,
+ QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_concurrent_policy - Defines attributes
+ * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG:
* u8 attribute. Configures the concurrent STA policy configuration.
* Possible values are defined in enum qca_wlan_concurrent_sta_policy_config.
+
+ * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG:
+ * u8 attribute. Configures the concurrent AP policy configuration.
+ * Possible values are defined in enum qca_wlan_concurrent_ap_policy_config.
*/
-enum qca_wlan_vendor_attr_concurrent_sta_policy {
- QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_INVALID = 0,
- QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG = 1,
+enum qca_wlan_vendor_attr_concurrent_policy {
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG = 1,
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG = 2,
/* keep last */
- QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST,
- QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX =
- QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST - 1,
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AFTER_LAST - 1,
};
+/* Compatibility defines for previously used enum
+ * qca_wlan_vendor_attr_concurrent_policy names. These values should not be used
+ * in any new implementation.
+ */
+#define QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG \
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG
+#define QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX \
+ QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX
+#define qca_wlan_vendor_attr_concurrent_sta_policy \
+ qca_wlan_vendor_attr_concurrent_policy
+
/**
* enum qca_sta_connect_fail_reason_codes - Defines values carried
* by QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE vendor
@@ -11821,6 +12069,82 @@
};
/**
+ * enum qca_wlan_vendor_attr_supported_radio_cfg - Attributes for
+ * radio configurations present in each radio combination.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND: u32 attribute indicates
+ * the band info in the radio configuration. Uses the enum qca_set_band values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA: u8 attribute indicates
+ * the number of antennas info in the radio configuration.
+ */
+enum qca_wlan_vendor_attr_supported_radio_cfg {
+ QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND = 1,
+ QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_LAST,
+ QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_radio_combination - Attributes for
+ * radio combinations supported by the device.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS: Nested attribute
+ * provides the radio configurations present in the radio combination.
+ * Uses the enum qca_wlan_vendor_attr_supported_radio_cfg attributes.
+ * This attribute provides the values for radio combination matrix.
+ * For standalone config, the number of config values is one and the config
+ * carries the band and antenna information for standalone configuration. For
+ * Dual Band Simultaneous (DBS)/Single Band Simultaneous (SBS) mode
+ * configuration the number of config values is two and the config carries the
+ * band and antenna information for each simultaneous radio.
+ */
+enum qca_wlan_vendor_attr_radio_combination {
+ QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_LAST,
+ QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_MAX =
+ QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_radio_combination_matrix - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS: Nested attribute
+ * provides the radio combinations supported by the device.
+ * Uses the enum qca_wlan_vendor_attr_radio_combination attributes.
+ * For example, in the radio combination matrix for a device which has two
+ * radios, where one radio is capable of 2.4 GHz 2X2 only and another radio is
+ * capable of either 5 GHz or 6 GHz 2X2, the possible number of radio
+ * combinations is 5 and the radio combinations are
+ * {{{2.4 GHz 2X2}}, //Standalone 2.4 GHz
+ * {{5 GHz 2X2}}, //Standalone 5 GHz
+ * {{6 GHz 2X2}}, //Standalone 6 GHz
+ * {{2.4 GHz 2X2}, {5 GHz 2X2}}, //2.4 GHz + 5 GHz DBS
+ * {{2.4 GHz 2X2}, {6 GHz 2X2}}} //2.4 GHz + 6 GHz DBS
+ * The band and antenna info together as nested data provides one radio config.
+ * Standalone configuration has one config with band and antenna nested data.
+ * Dual Band Simultaneous (DBS)/Single Band Simultaneous (SBS) configuration
+ * have two nested band and antenna info data.
+ */
+enum qca_wlan_vendor_attr_radio_combination_matrix {
+ QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_LAST,
+ QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_MAX =
+ QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_mdns_offload - Attributes used by
* %QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD vendor command.
*
@@ -12198,4 +12522,1043 @@
QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_audio_data_path - Defines the data path to be used for audio
+ * traffic.
+ *
+ * @QCA_WLAN_AUDIO_DATA_PATH_VIA_HOST_PROCESSOR:
+ * Send audio traffic through the host processor.
+ * @QCA_WLAN_AUDIO_DATA_PATH_VIA_LOW_POWER_DSP:
+ * Send audio traffic using the low power DSP to/from the encoder.
+ */
+enum qca_wlan_audio_data_path {
+ QCA_WLAN_AUDIO_DATA_PATH_VIA_HOST_PROCESSOR = 0,
+ QCA_WLAN_AUDIO_DATA_PATH_VIA_LOW_POWER_DSP = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_pasn_action - Action to authenticate (and generate keys
+ * for) or drop existing PASN security association for the listed the
+ * peers. Used by QCA_WLAN_VENDOR_ATTR_PASN_ACTION and sent from the driver
+ * to userspace.
+ *
+ * @QCA_WLAN_VENDOR_PASN_ACTION_AUTH: Initiate PASN handshake with the peer
+ * devices indicated with %QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR.
+ * @QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT: Indication from
+ * the driver to userspace to inform that the existing PASN keys of the
+ * peer devices specified with %QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR are
+ * not valid anymore.
+ */
+enum qca_wlan_vendor_pasn_action {
+ QCA_WLAN_VENDOR_PASN_ACTION_AUTH,
+ QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_pasn_peer: Defines the nested attributes used in
+ * QCA_WLAN_VENDOR_ATTR_PASN_PEERS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR: This attribute is optional in the
+ * event from the driver to userspace and represents the local MAC address
+ * to be used for PASN handshake. When this attribute is present, userspace
+ * shall use the source address specified in this attribute by the driver
+ * for PASN handshake with peer device.
+ * This attribute is required in a command response from userspace to the
+ * driver and represents the MAC address that was used in PASN handshake
+ * with the peer device.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR: Indicates the MAC address of the
+ * peer device to which PASN handshake is requested in an event from the
+ * driver to userspace when QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * QCA_WLAN_VENDOR_PASN_ACTION_AUTH.
+ * Indicates the MAC address of the peer device for which the keys are to
+ * be invalidated in an event from the driver to userspace when
+ * QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT.
+ * Indicates the MAC address of the peer device for which the status is
+ * being sent in a status report from userspace to the driver.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED: NLA_FLAG attribute used
+ * in the event from the driver to userspace. When set, userspace is
+ * required to derive LTF key seed from KDK and set it to the driver.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS: NLA_FLAG attribute. This
+ * attribute is used in the command response from userspace to the driver.
+ * If present, it indicates the successful PASN handshake with the peer. If
+ * this flag is not present, it indicates that the PASN handshake with the
+ * peer device failed.
+ */
+enum qca_wlan_vendor_attr_pasn_peer {
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR = 2,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED = 3,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX =
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_pasn: Defines the attributes used in the
+ * QCA_NL80211_VENDOR_SUBCMD_PASN command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PASN_ACTION: u32 attribute, possible values are
+ * defined in enum qca_wlan_vendor_pasn_action and used only in an event
+ * from the driver to userspace.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEERS: Nested attribute, used to pass PASN peer
+ * details for each peer and used in both an event and a command response.
+ * The nested attributes used inside QCA_WLAN_VENDOR_ATTR_PASN_PEERS are
+ * defined in enum qca_wlan_vendor_attr_pasn_peer.
+ */
+enum qca_wlan_vendor_attr_pasn {
+ QCA_WLAN_VENDOR_ATTR_PASN_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PASN_ACTION = 1,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEERS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PASN_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PASN_MAX =
+ QCA_WLAN_VENDOR_ATTR_PASN_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_secure_ranging_ctx_action - Used to add or delete
+ * the ranging security context derived from PASN for each peer. Used in
+ * QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION.
+ *
+ * @QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD: Add the secure ranging
+ * context for the peer.
+ * @QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE: Delete the secure ranging
+ * context for the peer.
+ */
+enum qca_wlan_vendor_secure_ranging_ctx_action {
+ QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD,
+ QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE,
+};
+
+/**
+ * enum qca_wlan_vendor_sha_type - SHA types. Used to configure the SHA type
+ * used for deriving PASN keys to the driver. Used in
+ * QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE
+ * @QCA_WLAN_VENDOR_SHA_256: SHA-256
+ * @QCA_WLAN_VENDOR_SHA_384: SHA-384
+ */
+enum qca_wlan_vendor_sha_type {
+ QCA_WLAN_VENDOR_SHA_256,
+ QCA_WLAN_VENDOR_SHA_384,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_secure_ranging_ctx: Defines the attributes used
+ * to set security context for the PASN peer from userspace to the driver.
+ * Used with QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION: u32 attribute, possible
+ * values are defined in enum qca_wlan_vendor_secure_ranging_ctx_action
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR: The local MAC address that
+ * was used during the PASN handshake.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR: The MAC address of
+ * the peer device for which secure ranging context is being configured.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE: u32 attribute, defines the
+ * hash algorithm to be used, possible values are defined in enum
+ * qca_wlan_vendor_sha_type.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK: Variable length attribute, holds
+ * the temporal key generated from the PASN handshake. The length of this
+ * attribute is dependent on the value of
+ * %QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER.
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER: cipher suite to use with the
+ * TK, u32, as defined in IEEE Std 802.11-2020, 9.4.2.24.2 (Cipher suites)
+ * (e.g., 0x000FAC04).
+ * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED: Variable length
+ * attribute, holds the LTF keyseed derived from KDK of PASN handshake.
+ * The length of this attribute is dependent on the value of
+ * %QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE.
+
+ */
+enum qca_wlan_vendor_attr_secure_ranging_ctx {
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION = 1,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR = 2,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR = 3,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE = 4,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK = 5,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER = 6,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX =
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload_filter - Attributes used
+ * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER
+ * nested attribute. The packets that match a filter will be replied with
+ * attributes configured in %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4:
+ * u32 attribute. Destination IPv4 address in network byte order, the
+ * IPv4 packets with different address will be filtered out.
+ * This attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4_IS_BC:
+ * Flag attribute. If it's present, indicates that
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4 is a broadcast
+ * address; while if not, indicates that the address is a unicast/multicast
+ * address.
+ * This attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV6:
+ * NLA_BINARY attribute, length is 16 bytes.
+ * Destination IPv6 address in network byte order, the IPv6 packets
+ * with different destination address will be filtered out.
+ * This attribute is optional.
+ *
+ * At least one of %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4 and
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV6 must be configured.
+ * Packets on both IPv4 and IPv6 will be processed if both are configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_PORT:
+ * u16 attribute. Destination UDP port, the packets with different destination
+ * UDP port will be filtered out.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_OFFSET:
+ * u32 attribute. Represents the offset (in UDP payload) of the data
+ * to be matched.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_DATA:
+ * NLA_BINARY attribute, the maximum allowed size is 16 bytes.
+ * Binary data that is compared bit-by-bit against the data (specified
+ * by %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_OFFSET) in UDP
+ * payload, the packets don't match will be filtered out.
+ * This attribute is mandatory.
+ */
+enum qca_wlan_vendor_attr_coap_offload_filter {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4 = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4_IS_BC = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV6 = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_PORT = 4,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_OFFSET = 5,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_DATA = 6,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload_reply - Attributes used
+ * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY nested attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV4:
+ * u32 attribute. Source address (in network byte order) for replying
+ * the matching broadcast/multicast IPv4 packets.
+ * This attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV6:
+ * NLA_BINARY attribute, length is 16 bytes.
+ * Source address (in network byte order) for replying the matching
+ * multicast IPv6 packets.
+ * This attribute is optional.
+ *
+ * For broadcast/multicast offload reply, one of
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV4 and
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV6 or both must be
+ * configured according to version of the IP address(es) configured in
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER;
+ * while for unicast case, firmware will take the destination IP address
+ * in the received matching packet as the source address for replying.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER:
+ * Nested attribute. Filter for the received UDP packets, only the matching
+ * packets will be replied and cached.
+ * See enum qca_wlan_vendor_attr_coap_offload_filter for list of supported
+ * attributes.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_MSG:
+ * NLA_BINARY attribute, the maximum allowed size is 1152 bytes.
+ * CoAP message (UDP payload) to be sent upon receiving matching packets.
+ * Firmware is responsible for adding any necessary protocol headers.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_CACHE_EXPTIME:
+ * u32 attribute. Expiration time in milliseconds of the cached CoAP messages.
+ * A cached message will be dropped by firmware if it's expired.
+ * This attribute is optional. A default value of 40000 will be used in the
+ * absence of it.
+ */
+enum qca_wlan_vendor_attr_coap_offload_reply {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV4 = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV6 = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_MSG = 4,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_CACHE_EXPTIME = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload_tx_ipv4 - Represents parameters for
+ * CoAP message (UDP) transmitting on IPv4.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_ADDR:
+ * u32 attribute. Source address (in network byte order) for transmitting
+ * packets on IPv4.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_PORT:
+ * u16 attribute. Source UDP port.
+ * This attribute is optional, a random port is taken if it's not present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_ADDR:
+ * u32 attribute. Destination IPv4 address (in network byte order).
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_IS_BC:
+ * Flag attribute. If it's present, indicates that
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_ADDR is a broadcast
+ * address; while if not, indicates that the address is unicast/multicast
+ * address.
+ * This attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_PORT:
+ * u16 attribute. Destination UDP port.
+ * This attribute is mandatory.
+ */
+enum qca_wlan_vendor_attr_coap_offload_tx_ipv4 {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_PORT = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_ADDR = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_IS_BC = 4,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_PORT = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload_tx_ipv6 - Represents parameters for
+ * CoAP message (UDP) transmitting on IPv6.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_ADDR:
+ * NLA_BINARY attribute, length is 16 bytes.
+ * Source address (in network byte order) for transmitting packets on IPv6.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_PORT:
+ * u16 attribute. Source UDP port.
+ * This attribute is optional, a random port is taken if it's not present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_ADDR:
+ * NLA_BINARY attribute, length is 16 bytes.
+ * Destination IPv6 address (in network byte order).
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_PORT:
+ * u16 attribute. Destination UDP port.
+ * This attribute is mandatory.
+ */
+enum qca_wlan_vendor_attr_coap_offload_tx_ipv6 {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_PORT = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_ADDR = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_PORT = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload_periodic_tx - Attributes used
+ * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX nested attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV4:
+ * Nested attribute. The IPv4 source/destination address/port for offload
+ * transmitting. See enum qca_wlan_vendor_attr_coap_offload_tx_ipv4 for the list
+ * of supported attributes.
+ * This attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV6:
+ * Nested attribute. The IPv6 source/destination address/port for offload
+ * transmitting. See enum qca_wlan_vendor_attr_coap_offload_tx_ipv6 for the list
+ * of supported attributes.
+ * This attribute is optional.
+ *
+ * At least one of %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV4 and
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV6 must be configured.
+ * Firmware will transmit the packets on both IPv4 and IPv6 if both are
+ * configured.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_PERIOD:
+ * u32 attribute. Period in milliseconds for the periodic transmitting.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_MSG:
+ * NLA_BINARY attribute, the maximum allowed size is 1152 bytes.
+ * CoAP message (UDP payload) to be periodically transmitted. Firmware
+ * is responsible for adding any necessary protocol headers.
+ * This attribute is mandatory.
+ */
+enum qca_wlan_vendor_attr_coap_offload_periodic_tx {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV4 = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV6 = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_PERIOD = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_MSG = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload_cache_info - Attributes used
+ * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES nested attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS:
+ * u64 attribute. Received time (since system booted in microseconds) of
+ * the cached CoAP message.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4:
+ * u32 attribute. Source IPv4 address (in network byte order) of the cached
+ * CoAP message.
+ * This attribute is optional.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV6:
+ * NLA_BINARY attribute, length is 16 bytes.
+ * Source IPv6 address (in network byte order) of the cached CoAP message.
+ * This attribute is optional.
+ *
+ * At most and at least one of
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 and
+ * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV6 is given for
+ * an entry.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG:
+ * NLA_BINARY attribute, the maximum allowed size is 1152 bytes.
+ * The cached CoAP message (UDP payload). If the actual message size is
+ * greater than the maximum size, it will be truncated and leaving only
+ * the first 1152 bytes.
+ * This attribute is mandatory.
+ */
+enum qca_wlan_vendor_attr_coap_offload_cache_info {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV6 = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_coap_offload_action - Actions for
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD.
+ *
+ * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE:
+ * Enable CoAP offload reply.
+ * If it's enabled, firmware will start offload processing on each suspend
+ * and stop on each resume.
+ *
+ * Offload reply on match works as follows:
+ * Reply the packets that match the filter with the given CoAP
+ * message (with necessary protocol headers), increase the CoAP message
+ * ID in the given CoAP message by one for the next use after each successful
+ * transmission, and try to store the information of the received packet,
+ * including the received time, source IP address, and CoAP message (UDP
+ * payload).
+ *
+ * Firmware has a limit to the maximum stored entries, it takes the source IP
+ * address as the key of an entry, and keeps at most one entry for each key.
+ * A packet won't be stored if no entry for the same key is present and the
+ * total number of the existing unexpired entries reaches the maximum value.
+ *
+ * If any configured item is changed, user space should disable offload reply
+ * first and then issue a new enable request.
+ *
+ * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE:
+ * Disable CoAP offload reply and return information of any cached CoAP
+ * messages.
+ *
+ * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE:
+ * Enable CoAP offload periodic transmitting.
+ * If it's enabled, firmware will start offload periodic transmitting on
+ * each suspend and stop on each resume.
+ *
+ * Offload periodic transmitting works as follows:
+ * Send the given CoAP message (with necessary protocol headers) with the given
+ * source/destination IP address/UDP port periodically based on the given
+ * period and increase the CoAP message ID in the given CoAP message by one
+ * for the next use after each successful transmission.
+ *
+ * If any configured item is changed, user space should disable offload
+ * periodic transmitting first and then issue a new enable request.
+ *
+ * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE:
+ * Disable CoAP offload periodic transmitting.
+ *
+ * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET:
+ * Get information of the CoAP messages cached during offload reply
+ * processing. The cache is cleared after retrieval.
+ */
+enum qca_wlan_vendor_coap_offload_action {
+ QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE = 0,
+ QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE = 1,
+ QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE = 2,
+ QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE = 3,
+ QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET = 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_coap_offload - Used by the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD.
+ * This is used to set parameters for CoAP offload processing, or get
+ * cached CoAP messages from firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION:
+ * u32 attribute. Action to take in this vendor command.
+ * See enum qca_wlan_vendor_coap_offload_action for supported actions.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REQ_ID:
+ * u32 attribute. Represents the Request ID for the CoAP offload
+ * configuration, which can help to identify the user entity starting
+ * the CoAP offload processing and accordingly stop the respective
+ * ones/get the cached CoAP messages with the matching ID.
+ * This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY:
+ * Nested attribute. Parameters for offload reply.
+ * See enum qca_wlan_vendor_attr_coap_offload_reply for the list of
+ * supported attributes.
+ * This attribute is mandatory if %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION
+ * is QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE, and is ignored
+ * otherwise.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX:
+ * Nested attribute. Parameters for offload periodic transmitting.
+ * See enum qca_wlan_vendor_attr_coap_offload_periodic_tx for the list of
+ * supported attributes.
+ * This attribute is mandatory if %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION is
+ * QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE, and is ignored
+ * otherwise.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES:
+ * Array of nested attributes. Information of the cached CoAP messages,
+ * where each entry is taken from
+ * enum qca_wlan_vendor_attr_coap_offload_cache_info.
+ * This attribute is used for reporting the cached CoAP messages
+ * in reply for command in which %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION
+ * is QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET or
+ * QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE. It means there is no
+ * cached item if this attribute is not present.
+ */
+enum qca_wlan_vendor_attr_coap_offload {
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION = 1,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REQ_ID = 2,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY = 3,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX = 4,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_scs_rule_config - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG to configure Stream Classification
+ * Service (SCS) rule.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_RULE_ID: Mandatory u32 attribute.
+ * Represents the unique id of SCS rule to be configured.
+
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_REQUEST_TYPE: Mandatory u8 attribute.
+ * Represents the request type: add, remove, or change.
+ * Values as defined in IEEE Std 802.11-2020, Table 9-246 (SCS Request
+ * Type definitions).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_OUTPUT_TID: Mandatory u8 attribute
+ * in case of add/change request type.
+ * Represents the output traffic identifier (TID) to be assigned to the flow
+ * matching the rule.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_CLASSIFIER_TYPE: Mandatory u8
+ * attribute in case of add/change request type.
+ * Represents type of classifier parameters present in SCS rule.
+ * Refer IEEE Std 802.11-2020 Table 9-164 (Frame classifier type).
+ * Only classifier types 4 and 10 are supported for SCS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_VERSION: Mandatory u8 attribute
+ * in case of add/change request type when classifier type is TCLAS4.
+ * Represents the IP version (4: IPv4, 6: IPv6) of the rule.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV4_ADDR: Optional
+ * attribute in case of add/change request type when classifier type is TCLAS4
+ * and version attribute is IPv4.
+ * Represents the source IPv4 address in the rule which is to be compared
+ * against the source IP address in the IPv4 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV4_ADDR: Optional
+ * attribute in case of add/change request type when classifier type is TCLAS4
+ * and version attribute is IPv4.
+ * Represents the destination IPv4 address in the rule which is to be compared
+ * against the destination IP address in the IPv4 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV6_ADDR: Optional
+ * attribute in case of add/change request type when classifier type is TCLAS4
+ * and version attribute is IPv6.
+ * Represents the source IPv6 address in the rule which is to be compared
+ * against the source IP address in the IPv6 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV6_ADDR: Optional
+ * attribute in case of add/change request type when classifier type is TCLAS4
+ * and version attribute is IPv6.
+ * Represents the destination IPv6 address in the rule which is to be compared
+ * against the destination IP address in the IPv6 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_PORT: Optional u16 attribute
+ * in case of add/change request type when classifier type is TCLAS4.
+ * Represents the source port number in the rule which is to be compared against
+ * the source port number in the protocol header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_PORT: Optional u16 attribute
+ * in case of add/change request type when classifier type is TCLAS4.
+ * Represents the destination port number in the rule which is to be compared
+ * against the destination port number in the protocol header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DSCP: Optional u8 attribute
+ * in case of add/change request type when classifier type is TCLAS4.
+ * Represents the DSCP value in the rule which is to be compared against the
+ * DSCP field present in the IP header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_NEXT_HEADER: Optional u8
+ * attribute in case of add/change request type when classifier type is TCLAS4.
+ * Represents the protocol/next header in the rule which is to be compared
+ * against the protocol/next header field present in the IPv4/IPv6 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_FLOW_LABEL: Optional
+ * attribute of size 3 bytes present in case of add/change request type
+ * when classifier type is TCLAS4 and version is IPv6.
+ * Represents the flow label value in the rule which is to be compared against
+ * the flow label field present in the IPv6 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_PROTOCOL_INSTANCE: Optional u8
+ * attribute in case of add/change request type when classifier type is TCLAS10.
+ * Represents the protocol instance number in the rule.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER: Optional u8
+ * attribute in case of add/change request type when classifier type is TCLAS10.
+ * Represents the protocol/next header in the rule which is to be compared
+ * against the protocol/next header field present in the IPv4/IPv6 header.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_MASK: Optional
+ * attribute of variable length present when request type is add/change and
+ * classifier type is TCLAS10.
+ * Represents the mask to be used for masking the header contents of the header
+ * specified by QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER
+ * attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_VALUE: Optional
+ * attribute of variable length present when request type is add/change and
+ * classifier type is TCLAS10.
+ * Represents the value to be compared against after masking the header contents
+ * of the header specified by the
+ * QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER attribute with the
+ * filter mask specified by the
+ * QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_MASK attribute.
+ */
+enum qca_wlan_vendor_attr_scs_rule_config {
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_RULE_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_REQUEST_TYPE = 2,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_OUTPUT_TID = 3,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_CLASSIFIER_TYPE = 4,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_VERSION = 5,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV4_ADDR = 6,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV4_ADDR = 7,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV6_ADDR = 8,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV6_ADDR = 9,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_PORT = 10,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_PORT = 11,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DSCP = 12,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_NEXT_HEADER = 13,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_FLOW_LABEL = 14,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_PROTOCOL_INSTANCE = 15,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER = 16,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_MASK = 17,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_VALUE = 18,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mlo_links - Definition of attributes used inside
+ * nested attribute QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID: u8 attribute, link ID of this MLO link.
+ * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR: Own MAC address of this MLO link.
+ * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID: AP link MAC address of this MLO link.
+ */
+enum qca_wlan_vendor_attr_mlo_links {
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR = 2,
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID = 3,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX =
+ QCA_WLAN_VENDOR_ATTR_MLO_LINK_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_sar_version - This describes the current SAR version
+ * used in the firmware.
+ *
+ * @QCA_WLAN_VENDOR_SAR_VERSION_1: The firmware supports legacy SAR.
+ * In legacy SAR, the firmware supports 5 static and 1 user defined SAR limits.
+ *
+ * @QCA_WLAN_VENDOR_SAR_VERSION_2: The firmware supports SAR version 2,
+ * i.e., SAR Non DBS mode. In SAR version 2, the firmware has 6 SAR tables for
+ * each CTL group. So user can select up to 6 SAR indexes from the current CTL
+ * groups.
+ *
+ * @QCA_WLAN_VENDOR_SAR_VERSION_3: The firmware supports SAR version 3,
+ * i.e., SAR DBS mode. In SAR version 3, the firmware has 6 SAR tables for each
+ * CTL group but user can choose up to 3 SAR set index only, as the top half
+ * of the SAR index (0 to 2) is used for non DBS purpose and the bottom half of
+ * the SAR index (3 to 5) is used for DBS mode.
+ */
+enum qca_wlan_vendor_sar_version {
+ QCA_WLAN_VENDOR_SAR_VERSION_INVALID = 0,
+ QCA_WLAN_VENDOR_SAR_VERSION_1 = 1,
+ QCA_WLAN_VENDOR_SAR_VERSION_2 = 2,
+ QCA_WLAN_VENDOR_SAR_VERSION_3 = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_sar_ctl_group_state - This describes whether
+ * CTL grouping is enabled or disabled in the firmware.
+ *
+ * @QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_ENABLED: CTL grouping
+ * is enabled in firmware.
+ *
+ * @QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_DISABLED: CTL grouping
+ * is disabled in firmware.
+ *
+ */
+enum qca_wlan_vendor_sar_ctl_group_state {
+ QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_INVALID = 0,
+ QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_ENABLED = 1,
+ QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_DISABLED = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sar_capability - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY to get SAR capabilities
+ * supported by the firmware.
+
+ * @QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION:
+ * u32 attribute. This field describes current SAR version supported by the
+ * firmware.
+ * See enum qca_wlan_vendor_sar_version for more information.
+ * This attribute is mandatory.
+
+ * @QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_CTL_GROUP_STATE:
+ * u32 attribute. This field describes whether CTL groups are enabled
+ * or disabled in the firmware.
+ * See enum qca_wlan_vendor_sar_ctl_group_state for more information.
+ * This attribute is optional.
+ */
+
+enum qca_wlan_vendor_attr_sar_capability {
+ QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION = 1,
+ QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_CTL_GROUP_STATE = 2,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sr_stats - Attributes for Spatial Reuse statistics.
+ * These statistics are sent from the driver in a response when userspace
+ * queries to get the statistics using the operation
+ * %QCA_WLAN_SR_OPERATION_GET_STATS. These statistics are reset
+ * by the driver when the SR feature is enabled, when the driver receives
+ * %QCA_WLAN_SR_OPERATION_CLEAR_STATS operation, or when disconnected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_OPPORTUNITIES_COUNT: u32 attribute.
+ * Mandatory only when non-SRG is supported by the AP and optional otherwise.
+ * This represents the number of non-SRG TX opportunities.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_TRIED_COUNT: u32 attribute.
+ * Mandatory only when non-SRG is supported by the AP and optional otherwise.
+ * This represents the number of non-SRG PPDUs tried to transmit.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_SUCCESS_COUNT: u32 attribute.
+ * Mandatory only when non-SRG is supported by the AP and optional otherwise.
+ * This represents the number of non-SRG PPDUs successfully transmitted.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_OPPORTUNITIES_COUNT: u32 attribute.
+ * Mandatory only when SRG is supported by the AP and optional otherwise.
+ * This represents the number of SRG TX opportunities.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_TRIED_COUNT: u32 attribute.
+ * Mandatory only when SRG is supported by the AP and optional otherwise.
+ * This represents the number of SRG PPDUs tried to transmit.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_SUCCESS_COUNT: u32 attribute.
+ * Mandatory only when SRG is supported by the AP and optional otherwise.
+ * This represents the number of SRG PPDUs successfully transmitted.
+ */
+enum qca_wlan_vendor_attr_sr_stats {
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_OPPORTUNITIES_COUNT = 1,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_TRIED_COUNT = 2,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_SUCCESS_COUNT = 3,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_OPPORTUNITIES_COUNT = 4,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_TRIED_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_SUCCESS_COUNT = 6,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_SR_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_sr_reason_code - Defines the different reason codes used in
+ * Spatial Reuse feature.
+ *
+ * @QCA_WLAN_SR_REASON_CODE_ROAMING: The SR feature is disabled/enabled due to
+ * roaming to an AP that doesn't support/supports SR feature, respectively.
+ *
+ * @QCA_WLAN_SR_REASON_CODE_CONCURRENCY: The SR feature is disabled/enabled due
+ * to change in concurrent interfaces that are supported by the driver.
+ */
+enum qca_wlan_sr_reason_code {
+ QCA_WLAN_SR_REASON_CODE_ROAMING = 0,
+ QCA_WLAN_SR_REASON_CODE_CONCURRENCY = 1,
+};
+
+/**
+ * enum qca_wlan_sr_operation - Defines the different types of SR operations.
+ * The values are used inside attribute %QCA_WLAN_VENDOR_ATTR_SR_OPERATION.
+ *
+ * @QCA_WLAN_SR_OPERATION_SR_ENABLE: Userspace sends this operation to the
+ * driver to enable the Spatial Reuse feature. Attributes
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD and
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD are used with this
+ * operation.
+ *
+ * @QCA_WLAN_SR_OPERATION_SR_DISABLE: Userspace sends this operation to the
+ * driver to disable the Spatial Reuse feature.
+ *
+ * @QCA_WLAN_SR_OPERATION_SR_SUSPEND: The driver uses this operation in an
+ * asynchronous event sent to userspace when the SR feature is disabled.
+ * The disable reason is encoded in QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE
+ * and sent along with the asynchronous event.
+ *
+ * @QCA_WLAN_SR_OPERATION_SR_RESUME: The driver uses this operation in an
+ * asynchronous event when the SR feature is enabled again after the SR feature
+ * was suspended by the driver earlier. The enable reason is
+ * encoded in QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE. Attributes used are
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD and
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD.
+ *
+ * @QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT: This operation is
+ * used to prohibit PSR-based spatial reuse and non-SRG OBSS PD-based spatial
+ * reuse transmissions. Userspace sends this operation to the driver.
+ * The driver/firmware upon receiving this operation shall prohibit PSR-based
+ * spatial reuse and non-SRG OBSS PD-based spatial reuse transmissions.
+ *
+ * @QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW: This operation is
+ * used to allow PSR-based spatial reuse and non-SRG OBSS PD-based spatial
+ * reuse transmissions. Userspace sends this operation to the driver.
+ * The driver/firmware upon receiving this operation shall allow PSR-based
+ * spatial reuse and non-SRG OBSS PD-based spatial reuse transmissions.
+ *
+ * @QCA_WLAN_SR_OPERATION_GET_STATS: Userspace sends this operation to the
+ * driver to get the SR statistics and the driver sends a synchronous response
+ * with the attributes defined in enum qca_wlan_vendor_attr_sr_stats using the
+ * nested attribute %QCA_WLAN_VENDOR_ATTR_SR_STATS.
+ *
+ * @QCA_WLAN_SR_OPERATION_CLEAR_STATS: Userspace sends this operation to the
+ * driver to clear the SR statistics and upon receiving this operation
+ * the driver/firmware shall clear the SR statistics.
+ *
+ * @QCA_WLAN_SR_OPERATION_GET_PARAMS: Userspace sends this operation to the
+ * driver to get the SR parameters and the driver sends the synchronous response
+ * with the following required attributes:
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW.
+ *
+ * @QCA_WLAN_SR_OPERATION_UPDATE_PARAMS: The driver uses this operation in an
+ * asynchronous event to userspace to update any changes in SR parameters.
+ * The following attributes are used with this operation:
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE,
+ * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW.
+ */
+enum qca_wlan_sr_operation {
+ QCA_WLAN_SR_OPERATION_SR_ENABLE = 0,
+ QCA_WLAN_SR_OPERATION_SR_DISABLE = 1,
+ QCA_WLAN_SR_OPERATION_SR_SUSPEND = 2,
+ QCA_WLAN_SR_OPERATION_SR_RESUME = 3,
+ QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT = 4,
+ QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW = 5,
+ QCA_WLAN_SR_OPERATION_GET_STATS = 6,
+ QCA_WLAN_SR_OPERATION_CLEAR_STATS = 7,
+ QCA_WLAN_SR_OPERATION_GET_PARAMS = 8,
+ QCA_WLAN_SR_OPERATION_UPDATE_PARAMS = 9,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sr_params - Defines attributes for SR configuration
+ * parameters used by attribute %QCA_WLAN_VENDOR_ATTR_SR_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE: Flag attribute.
+ * This attribute is optionally set in response to
+ * %QCA_WLAN_SR_OPERATION_GET_PARAMS and in request when operation is set to
+ * %QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT. Refer IEEE Std
+ * 802.11ax-2021 Figure 9-788r-SR Control field format to understand more
+ * about HESIGA_Spatial_reuse_value15_allowed.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW: Flag attribute.
+ * This attribute is used in response to %QCA_WLAN_SR_OPERATION_GET_PARAMS
+ * operation. This indicates whether non-SRG OBSS PD SR transmissions are
+ * allowed or not at non-AP STAs that are associated with the AP. If present
+ * non-SRG OBSS PD SR transmissions are not allowed else are allowed.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET: Optional u8
+ * attribute. This attribute is used in response to
+ * %QCA_WLAN_SR_OPERATION_GET_PARAMS operation. This indicates the SRG OBSS PD
+ * Min Offset field which contains an unsigned integer that is added to -82 dBm
+ * to generate the value of the SRG OBSS PD Min parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET: Optional u8
+ * attribute. This attribute is used in response to
+ * %QCA_WLAN_SR_OPERATION_GET_PARAMS operation. This indicates the SRG OBSS PD
+ * Max Offset field which contains an unsigned integer that is added to -82 dBm
+ * to generate the value of the SRG OBSS PD Max parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET: Optional u8
+ * attribute. This attribute is used in response to
+ * %QCA_WLAN_SR_OPERATION_GET_PARAMS operation. This indicates the Non-SRG OBSS
+ * PD Max Offset field which contains an unsigned integer that is added to -82
+ * dBm to generate the value of the Non-SRG OBSS PD Max parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD: s32 attribute (in dBm).
+ * Userspace optionally sends this attribute with
+ * %QCA_WLAN_SR_OPERATION_SR_ENABLE operation to the driver to specify the
+ * preferred SRG PD threshold. The driver shall send this attribute to
+ * userspace in SR resume event to indicate the PD threshold being used for SR.
+ * When there is change in SRG PD threshold (for example, due to roaming, etc.)
+ * the driver shall indicate the userspace the newly configured SRG PD threshold
+ * using an asynchronous event.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD: s32 attribute (in dBm).
+ * Userspace optionally sends this attribute with
+ * %QCA_WLAN_SR_OPERATION_SR_ENABLE operation to the driver to specify the
+ * preferred non-SRG PD threshold. The driver shall send this attribute to
+ * userspace in SR resume event to indicate the PD threshold being used for SR.
+ * When there is change in non-SRG PD threshold (for example, due to roaming,
+ * etc.) the driver shall indicate the userspace the newly configured non-SRG PD
+ * threshold using an asynchronous event.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE: u32 attribute. The possible
+ * values are defined in enum qca_wlan_sr_reason_code. This
+ * attribute is used with %QCA_WLAN_SR_OPERATION_SR_RESUME and
+ * %QCA_WLAN_SR_OPERATION_SR_SUSPEND operations.
+ */
+enum qca_wlan_vendor_attr_sr_params {
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE = 1,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW = 2,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET = 3,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET = 4,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET = 5,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD = 6,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD = 7,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE = 8,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX =
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sr - Defines the attributes used by the vendor
+ * command QCA_NL80211_VENDOR_SUBCMD_SR.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_OPERATION: Mandatory u8 attribute for all requests
+ * from userspace to the driver. Possible values are defined in enum
+ * qca_wlan_sr_operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS: Nested attribute, contains the SR
+ * configuration parameters. The possible attributes inside this attribute are
+ * defined in enum qca_wlan_vendor_attr_sr_params.
+ * This attribute is used when QCA_WLAN_VENDOR_ATTR_SR_OPERATION is set to
+ * %QCA_WLAN_SR_OPERATION_SR_ENABLE in requests from userspace to the driver and
+ * also in response from the driver to userspace when the response is sent for
+ * %QCA_WLAN_SR_OPERATION_GET_PARAMS.
+ * The driver uses this attribute in asynchronous events in which the operation
+ * is set to %QCA_WLAN_SR_OPERATION_SR_RESUME,
+ * %QCA_WLAN_SR_OPERATION_SR_SUSPEND or %QCA_WLAN_SR_OPERATION_UPDATE_PARAMS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SR_STATS: Nested attribute, contains the SR
+ * statistics. These attributes used inside this are defined in enum
+ * qca_wlan_vendor_attr_sr_stats.
+ * This attribute is used in response from the driver to a command in which
+ * %QCA_WLAN_VENDOR_ATTR_SR_OPERATION is set to
+ * %QCA_WLAN_SR_OPERATION_GET_STATS.
+ */
+enum qca_wlan_vendor_attr_sr {
+ QCA_WLAN_VENDOR_ATTR_SR_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SR_OPERATION = 1,
+ QCA_WLAN_VENDOR_ATTR_SR_PARAMS = 2,
+ QCA_WLAN_VENDOR_ATTR_SR_STATS = 3,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_SR_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SR_MAX =
+ QCA_WLAN_VENDOR_ATTR_SR_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index c0f154e..33c7e5f 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -9,6 +9,8 @@
#include "includes.h"
#include "common.h"
+#include "common/defs.h"
+#include "common/wpa_common.h"
#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
@@ -1520,10 +1522,11 @@
const u8 *salt;
struct wpabuf *rejected_groups = NULL;
u8 keyseed[SAE_MAX_HASH_LEN];
- u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN];
+ u8 keys[2 * SAE_MAX_HASH_LEN + SAE_PMK_LEN_MAX];
struct crypto_bignum *tmp;
int ret = -1;
size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
+ size_t pmk_len;
const u8 *addr[1];
size_t len[1];
@@ -1545,6 +1548,14 @@
hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
else
hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ if (wpa_key_mgmt_sae_ext_key(sae->akmp))
+ pmk_len = hash_len;
+ else
+ pmk_len = SAE_PMK_LEN;
+ wpa_printf(MSG_DEBUG, "SAE: Derive keys - H2E=%d AKMP=0x%x = %08x (%s)",
+ sae->h2e, sae->akmp,
+ wpa_akm_to_suite(sae->akmp),
+ wpa_key_mgmt_txt(sae->akmp, WPA_PROTO_RSN));
if (sae->h2e && (sae->tmp->own_rejected_groups ||
sae->tmp->peer_rejected_groups)) {
struct wpabuf *own, *peer;
@@ -1602,25 +1613,26 @@
if (sae->pk) {
if (sae_kdf_hash(hash_len, keyseed, "SAE-PK keys",
val, sae->tmp->order_len,
- keys, 2 * hash_len + SAE_PMK_LEN) < 0)
+ keys, 2 * hash_len + pmk_len) < 0)
goto fail;
} else {
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len,
- keys, hash_len + SAE_PMK_LEN) < 0)
+ keys, hash_len + pmk_len) < 0)
goto fail;
}
#else /* CONFIG_SAE_PK */
if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
val, sae->tmp->order_len,
- keys, hash_len + SAE_PMK_LEN) < 0)
+ keys, hash_len + pmk_len) < 0)
goto fail;
#endif /* !CONFIG_SAE_PK */
forced_memzero(keyseed, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, hash_len);
sae->tmp->kck_len = hash_len;
- os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
+ os_memcpy(sae->pmk, keys + hash_len, pmk_len);
+ sae->pmk_len = pmk_len;
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
#ifdef CONFIG_SAE_PK
if (sae->pk) {
@@ -1634,7 +1646,7 @@
forced_memzero(keys, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
sae->tmp->kck, sae->tmp->kck_len);
- wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, sae->pmk_len);
ret = 0;
fail:
@@ -1726,6 +1738,17 @@
token);
}
+ if (wpa_key_mgmt_sae_ext_key(sae->akmp)) {
+ u32 suite = wpa_akm_to_suite(sae->akmp);
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + RSN_SELECTOR_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_AKM_SUITE_SELECTOR);
+ RSN_SELECTOR_PUT(wpabuf_put(buf, RSN_SELECTOR_LEN), suite);
+ wpa_printf(MSG_DEBUG, "SAE: AKM Suite Selector: %08x", suite);
+ sae->own_akm_suite_selector = suite;
+ }
+
return 0;
}
@@ -1802,6 +1825,16 @@
}
+static int sae_is_akm_suite_selector_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 2 + 1 + RSN_SELECTOR_LEN &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + RSN_SELECTOR_LEN &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_AKM_SUITE_SELECTOR;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
size_t *token_len, int h2e)
@@ -2089,6 +2122,35 @@
}
+static int sae_parse_akm_suite_selector(struct sae_data *sae,
+ const u8 **pos, const u8 *end)
+{
+ const u8 *epos;
+ u8 len;
+
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ *pos, end - *pos);
+ if (!sae_is_akm_suite_selector_elem(*pos, end))
+ return WLAN_STATUS_SUCCESS;
+
+ epos = *pos;
+ epos++; /* skip IE type */
+ len = *epos++; /* IE length */
+ if (len > end - epos || len < 1)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ epos++; /* skip ext ID */
+ len--;
+
+ if (len < RSN_SELECTOR_LEN)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ sae->peer_akm_suite_selector = RSN_SELECTOR_GET(epos);
+ wpa_printf(MSG_DEBUG, "SAE: Received AKM Suite Selector: %08x",
+ sae->peer_akm_suite_selector);
+ *pos = epos + len;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
const u8 **token, size_t *token_len, int *allowed_groups,
int h2e)
@@ -2133,6 +2195,31 @@
if (h2e)
sae_parse_token_container(sae, pos, end, token, token_len);
+ /* Conditional AKM Suite Selector element */
+ if (h2e) {
+ res = sae_parse_akm_suite_selector(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ }
+
+ if (sae->own_akm_suite_selector &&
+ sae->own_akm_suite_selector != sae->peer_akm_suite_selector) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: AKM suite selector mismatch: own=%08x peer=%08x",
+ sae->own_akm_suite_selector,
+ sae->peer_akm_suite_selector);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (!sae->akmp) {
+ if (sae->peer_akm_suite_selector ==
+ RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
+ sae->akmp = WPA_KEY_MGMT_SAE_EXT_KEY;
+ else if (sae->peer_akm_suite_selector ==
+ RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY)
+ sae->akmp = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
+ }
+
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
diff --git a/src/common/sae.h b/src/common/sae.h
index 93fc5fb..6a6b0c8 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -11,6 +11,7 @@
#define SAE_KCK_LEN 32
#define SAE_PMK_LEN 32
+#define SAE_PMK_LEN_MAX 64
#define SAE_PMKID_LEN 16
#define SAE_MAX_PRIME_LEN 512
#define SAE_MAX_ECC_PRIME_LEN 66
@@ -104,7 +105,11 @@
struct sae_data {
enum sae_state state;
u16 send_confirm;
- u8 pmk[SAE_PMK_LEN];
+ u8 pmk[SAE_PMK_LEN_MAX];
+ size_t pmk_len;
+ int akmp; /* WPA_KEY_MGMT_* used in key derivation */
+ u32 own_akm_suite_selector;
+ u32 peer_akm_suite_selector;
u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
struct crypto_bignum *peer_commit_scalar_accepted;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 27336c9..da707e6 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -36,6 +36,9 @@
return pmk_len / 2;
case WPA_KEY_MGMT_OWE:
return pmk_len / 2;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return pmk_len / 2;
default:
return 16;
}
@@ -72,6 +75,9 @@
return pmk_len <= 32 ? 16 : 32;
case WPA_KEY_MGMT_OWE:
return pmk_len <= 32 ? 16 : 32;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return pmk_len <= 32 ? 16 : 32;
default:
return 16;
}
@@ -108,6 +114,9 @@
return pmk_len / 2;
case WPA_KEY_MGMT_OWE:
return pmk_len / 2;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return pmk_len / 2;
default:
return 16;
}
@@ -143,7 +152,8 @@
akmp == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_ft(akmp) ||
wpa_key_mgmt_sha256(akmp) ||
- wpa_key_mgmt_sae(akmp) ||
+ (wpa_key_mgmt_sae(akmp) &&
+ !wpa_key_mgmt_sae_ext_key(akmp)) ||
wpa_key_mgmt_suite_b(akmp);
}
@@ -223,6 +233,32 @@
wpa_printf(MSG_DEBUG,
"WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)");
return omac1_aes_128(key, buf, len, mic);
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - SAE-EXT-KEY)",
+ (unsigned int) key_len * 8 * 2);
+ if (key_len == 128 / 8) {
+ if (hmac_sha256(key, key_len, buf, len, hash))
+ return -1;
+#ifdef CONFIG_SHA384
+ } else if (key_len == 192 / 8) {
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ } else if (key_len == 256 / 8) {
+ if (hmac_sha512(key, key_len, buf, len, hash))
+ return -1;
+#endif /* CONFIG_SHA512 */
+ } else {
+ wpa_printf(MSG_INFO,
+ "SAE: Unsupported KCK length: %u",
+ (unsigned int) key_len);
+ return -1;
+ }
+ os_memcpy(mic, hash, key_len);
+ break;
#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
case WPA_KEY_MGMT_OSEN:
@@ -473,6 +509,36 @@
(unsigned int) pmk_len);
return -1;
#endif /* CONFIG_DPP */
+#ifdef CONFIG_SAE
+ } else if (wpa_key_mgmt_sae_ext_key(akmp)) {
+ if (pmk_len == 32) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: PTK derivation using PRF(SHA256)");
+ if (sha256_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#ifdef CONFIG_SHA384
+ } else if (pmk_len == 48) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: PTK derivation using PRF(SHA384)");
+ if (sha384_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ } else if (pmk_len == 64) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: PTK derivation using PRF(SHA512)");
+ if (sha512_prf(pmk, pmk_len, label, data, data_len,
+ tmp, ptk_len) < 0)
+ return -1;
+#endif /* CONFIG_SHA512 */
+ } else {
+ wpa_printf(MSG_INFO, "SAE: Unknown PMK length %u",
+ (unsigned int) pmk_len);
+ return -1;
+ }
+#endif /* CONFIG_SAE */
} else {
wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA1)");
if (sha1_prf(pmk, pmk_len, label, data, data_len, tmp,
@@ -1318,6 +1384,62 @@
/**
+ * wpa_ltf_keyseed - Compute LTF keyseed from KDK
+ * @ptk: Buffer that holds pairwise transient key
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher)
+{
+ u8 *buf;
+ size_t buf_len;
+ u8 hash[SHA384_MAC_LEN];
+ const u8 *kdk = ptk->kdk;
+ size_t kdk_len = ptk->kdk_len;
+ const char *label = "Secure LTF key seed";
+
+ if (!kdk || !kdk_len) {
+ wpa_printf(MSG_ERROR, "WPA: No KDK for LTF keyseed generation");
+ return -1;
+ }
+
+ buf = (u8 *)label;
+ buf_len = os_strlen(label);
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Secure LTF keyseed using HMAC-SHA384");
+
+ if (hmac_sha384(kdk, kdk_len, buf, buf_len, hash)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: HMAC-SHA384 compute failed");
+ return -1;
+ }
+ os_memcpy(ptk->ltf_keyseed, hash, SHA384_MAC_LEN);
+ ptk->ltf_keyseed_len = SHA384_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ",
+ ptk->ltf_keyseed, ptk->ltf_keyseed_len);
+
+ } else {
+ wpa_printf(MSG_DEBUG, "WPA: LTF keyseed using HMAC-SHA256");
+
+ if (hmac_sha256(kdk, kdk_len, buf, buf_len, hash)) {
+ wpa_printf(MSG_ERROR,
+ "WPA: HMAC-SHA256 compute failed");
+ return -1;
+ }
+ os_memcpy(ptk->ltf_keyseed, hash, SHA256_MAC_LEN);
+ ptk->ltf_keyseed_len = SHA256_MAC_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ",
+ ptk->ltf_keyseed, ptk->ltf_keyseed_len);
+ }
+
+ return 0;
+}
+
+
+/**
* pasn_mic - Calculate PASN MIC
* @kck: The key confirmation key for the PASN PTKSA
* @akmp: Negotiated AKM
@@ -1479,8 +1601,12 @@
#ifdef CONFIG_SAE
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
return WPA_KEY_MGMT_SAE;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
+ return WPA_KEY_MGMT_SAE_EXT_KEY;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
return WPA_KEY_MGMT_FT_SAE;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY)
+ return WPA_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
@@ -2379,8 +2505,12 @@
return "WPS";
case WPA_KEY_MGMT_SAE:
return "SAE";
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ return "SAE-EXT-KEY";
case WPA_KEY_MGMT_FT_SAE:
return "FT-SAE";
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ return "FT-SAE-EXT-KEY";
case WPA_KEY_MGMT_OSEN:
return "OSEN";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
@@ -2441,8 +2571,12 @@
return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
if (akm & WPA_KEY_MGMT_SAE)
return RSN_AUTH_KEY_MGMT_SAE;
+ if (akm & WPA_KEY_MGMT_SAE_EXT_KEY)
+ return RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
if (akm & WPA_KEY_MGMT_FT_SAE)
return RSN_AUTH_KEY_MGMT_FT_SAE;
+ if (akm & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
+ return RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
if (akm & WPA_KEY_MGMT_OWE)
return RSN_AUTH_KEY_MGMT_OWE;
if (akm & WPA_KEY_MGMT_DPP)
@@ -3025,120 +3159,190 @@
*/
static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie)
{
- if (pos[1] == 0)
+ u8 len = pos[1];
+ size_t dlen = 2 + len;
+ u32 selector;
+ const u8 *p;
+ size_t left;
+ u8 link_id;
+ char title[50];
+ int ret;
+
+ if (len == 0)
return 1;
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ if (len < RSN_SELECTOR_LEN)
+ return 2;
+
+ p = pos + 2;
+ selector = RSN_SELECTOR_GET(p);
+ p += RSN_SELECTOR_LEN;
+ left = len - RSN_SELECTOR_LEN;
+
+ if (left >= 2 && selector == WPA_OUI_TYPE && p[0] == 1 && p[1] == 0) {
ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
+ ie->wpa_ie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
ie->wpa_ie, ie->wpa_ie_len);
return 0;
}
- if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ if (selector == OSEN_IE_VENDOR_TYPE) {
ie->osen = pos;
- ie->osen_len = pos[1] + 2;
+ ie->osen_len = dlen;
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = p;
+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) {
- ie->key_id = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= 2 && selector == RSN_KEY_DATA_KEYID) {
+ ie->key_id = p;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", pos, dlen);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left > 2 && selector == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = p;
+ ie->gtk_len = left;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", pos, dlen);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= ETH_ALEN && selector == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = p;
+ wpa_printf(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key: " MACSTR,
+ MAC2STR(ie->mac_addr));
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left > 2 && selector == RSN_KEY_DATA_IGTK) {
+ ie->igtk = p;
+ ie->igtk_len = left;
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) {
- ie->bigtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left > 2 && selector == RSN_KEY_DATA_BIGTK) {
+ ie->bigtk = p;
+ ie->bigtk_len = left;
wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ if (left >= 1 && selector == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = p;
wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ ie->ip_addr_req, left);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ if (left >= 3 * 4 && selector == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = p;
wpa_hexdump(MSG_DEBUG,
"WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ ie->ip_addr_alloc, left);
return 0;
}
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left > 2 && selector == RSN_KEY_DATA_OCI) {
+ ie->oci = p;
+ ie->oci_len = left;
wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) {
- ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN;
- ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN;
+ if (left >= 1 && selector == WFA_KEY_DATA_TRANSITION_DISABLE) {
+ ie->transition_disable = p;
+ ie->transition_disable_len = left;
wpa_hexdump(MSG_DEBUG,
"WPA: Transition Disable KDE in EAPOL-Key",
- pos, pos[1] + 2);
+ pos, dlen);
return 0;
}
- if (pos[1] >= RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_DPP) {
- ie->dpp_kde = pos + 2 + RSN_SELECTOR_LEN;
- ie->dpp_kde_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key",
- pos, pos[1] + 2);
+ if (left >= 2 && selector == WFA_KEY_DATA_DPP) {
+ ie->dpp_kde = p;
+ ie->dpp_kde_len = left;
+ wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", pos, dlen);
+ return 0;
+ }
+
+ if (left >= RSN_MLO_GTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_GTK) {
+ link_id = (p[0] & RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK) >>
+ RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_gtks |= BIT(link_id);
+ ie->mlo_gtk[link_id] = p;
+ ie->mlo_gtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO GTK KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
+ return 0;
+ }
+
+ if (left >= RSN_MLO_IGTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_IGTK) {
+ link_id = (p[8] & RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK) >>
+ RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_igtks |= BIT(link_id);
+ ie->mlo_igtk[link_id] = p;
+ ie->mlo_igtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO IGTK KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
+ return 0;
+ }
+
+ if (left >= RSN_MLO_BIGTK_KDE_PREFIX_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_BIGTK) {
+ link_id = (p[8] & RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK) >>
+ RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_bigtks |= BIT(link_id);
+ ie->mlo_bigtk[link_id] = p;
+ ie->mlo_bigtk_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO BIGTK KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump_key(MSG_DEBUG, title, pos, dlen);
+ return 0;
+ }
+
+ if (left >= RSN_MLO_LINK_KDE_FIXED_LENGTH &&
+ selector == RSN_KEY_DATA_MLO_LINK) {
+ link_id = (p[0] & RSN_MLO_LINK_KDE_LI_LINK_ID_MASK) >>
+ RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT;
+ if (link_id >= MAX_NUM_MLO_LINKS)
+ return 2;
+
+ ie->valid_mlo_links |= BIT(link_id);
+ ie->mlo_link[link_id] = p;
+ ie->mlo_link_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - MLO Link KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump(MSG_DEBUG, title, pos, dlen);
return 0;
}
@@ -3157,15 +3361,17 @@
{
const u8 *pos, *end;
int ret = 0;
+ size_t dlen = 0;
os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+ for (pos = buf, end = pos + len; end - pos > 1; pos += dlen) {
if (pos[0] == 0xdd &&
((pos == buf + len - 1) || pos[1] == 0)) {
/* Ignore padding */
break;
}
- if (2 + pos[1] > end - pos) {
+ dlen = 2 + pos[1];
+ if ((int) dlen > end - pos) {
wpa_printf(MSG_DEBUG,
"WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
pos[0], pos[1], (int) (pos - buf));
@@ -3175,22 +3381,22 @@
}
if (*pos == WLAN_EID_RSN) {
ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
+ ie->rsn_ie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
ie->rsn_ie, ie->rsn_ie_len);
} else if (*pos == WLAN_EID_RSNX) {
ie->rsnxe = pos;
- ie->rsnxe_len = pos[1] + 2;
+ ie->rsnxe_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
ie->rsnxe, ie->rsnxe_len);
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
+ ie->mdie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
ie->mdie, ie->mdie_len);
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
+ ie->ftie_len = dlen;
wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
ie->ftie, ie->ftie_len);
} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
@@ -3198,31 +3404,31 @@
ie->reassoc_deadline = pos;
wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
"in EAPOL-Key",
- ie->reassoc_deadline, pos[1] + 2);
+ ie->reassoc_deadline, dlen);
} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
ie->key_lifetime = pos;
wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
"in EAPOL-Key",
- ie->key_lifetime, pos[1] + 2);
+ ie->key_lifetime, dlen);
} else {
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
"EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
+ pos, dlen);
}
} else if (*pos == WLAN_EID_LINK_ID) {
if (pos[1] >= 18) {
ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
+ ie->lnkid_len = dlen;
}
} else if (*pos == WLAN_EID_EXT_CAPAB) {
ie->ext_capab = pos;
- ie->ext_capab_len = pos[1] + 2;
+ ie->ext_capab_len = dlen;
} else if (*pos == WLAN_EID_SUPP_RATES) {
ie->supp_rates = pos;
- ie->supp_rates_len = pos[1] + 2;
+ ie->supp_rates_len = dlen;
} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
ie->ext_supp_rates = pos;
- ie->ext_supp_rates_len = pos[1] + 2;
+ ie->ext_supp_rates_len = dlen;
} else if (*pos == WLAN_EID_HT_CAP &&
pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
ie->ht_capabilities = pos + 2;
@@ -3276,7 +3482,7 @@
} else {
wpa_hexdump(MSG_DEBUG,
"WPA: Unrecognized EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
+ pos, dlen);
}
}
@@ -3375,6 +3581,9 @@
case WPA_KEY_MGMT_SAE:
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
break;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
+ break;
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
case WPA_KEY_MGMT_FILS_SHA256:
@@ -3588,6 +3797,7 @@
switch (data->key_mgmt) {
#ifdef CONFIG_SAE
case WPA_KEY_MGMT_SAE:
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
/* fall through */
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index c28c55d..71b423c 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -81,8 +81,14 @@
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
#define RSN_AUTH_KEY_MGMT_OWE RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
-
+#define RSN_AUTH_KEY_MGMT_FT_PSK_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 19)
+#define RSN_AUTH_KEY_MGMT_PSK_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 20)
#define RSN_AUTH_KEY_MGMT_PASN RSN_SELECTOR(0x00, 0x0f, 0xac, 21)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384_UNRESTRICTED \
+ RSN_SELECTOR(0x00, 0x0f, 0xac, 22)
+#define RSN_AUTH_KEY_MGMT_802_1X_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 23)
+#define RSN_AUTH_KEY_MGMT_SAE_EXT_KEY RSN_SELECTOR(0x00, 0x0f, 0xac, 24)
+#define RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY RSN_SELECTOR(0x00, 0x0f, 0xac, 25)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
@@ -126,6 +132,10 @@
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
+#define RSN_KEY_DATA_MLO_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
+#define RSN_KEY_DATA_MLO_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
+#define RSN_KEY_DATA_MLO_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
+#define RSN_KEY_DATA_MLO_LINK RSN_SELECTOR(0x00, 0x0f, 0xac, 19)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
@@ -222,6 +232,7 @@
#define FILS_FT_MAX_LEN 48
#define WPA_PASN_KCK_LEN 32
#define WPA_PASN_MIC_MAX_LEN 24
+#define WPA_LTF_KEYSEED_MAX_LEN 48
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -234,12 +245,14 @@
u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
u8 kdk[WPA_KDK_MAX_LEN]; /* Key Derivation Key */
+ u8 ltf_keyseed[WPA_LTF_KEYSEED_MAX_LEN]; /* LTF Key seed */
size_t kck_len;
size_t kek_len;
size_t tk_len;
size_t kck2_len;
size_t kek2_len;
size_t kdk_len;
+ size_t ltf_keyseed_len;
int installed; /* 1 if key has already been installed to driver */
};
@@ -330,6 +343,40 @@
u8 bigtk[WPA_BIGTK_MAX_LEN];
} STRUCT_PACKED;
+#define RSN_MLO_GTK_KDE_PREFIX_LENGTH (1 + 6)
+#define RSN_MLO_GTK_KDE_PREFIX0_KEY_ID_MASK 0x03
+#define RSN_MLO_GTK_KDE_PREFIX0_TX 0x04
+#define RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_SHIFT 4
+#define RSN_MLO_GTK_KDE_PREFIX0_LINK_ID_MASK 0xF0
+
+#define RSN_MLO_IGTK_KDE_PREFIX_LENGTH (2 + 6 + 1)
+#define RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_SHIFT 4
+#define RSN_MLO_IGTK_KDE_PREFIX8_LINK_ID_MASK 0xF0
+struct rsn_mlo_igtk_kde {
+ u8 keyid[2];
+ u8 pn[6];
+ u8 prefix8;
+ u8 igtk[WPA_IGTK_MAX_LEN];
+} STRUCT_PACKED;
+
+#define RSN_MLO_BIGTK_KDE_PREFIX_LENGTH (2 + 6 + 1)
+#define RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_SHIFT 4
+#define RSN_MLO_BIGTK_KDE_PREFIX8_LINK_ID_MASK 0xF0
+struct rsn_mlo_bigtk_kde {
+ u8 keyid[2];
+ u8 pn[6];
+ u8 prefix8;
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+} STRUCT_PACKED;
+
+#define RSN_MLO_LINK_KDE_FIXED_LENGTH (1 + 6)
+#define RSN_MLO_LINK_KDE_LINK_INFO_INDEX 0
+#define RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT 0
+#define RSN_MLO_LINK_KDE_LI_LINK_ID_MASK 0x0F
+#define RSN_MLO_LINK_KDE_LI_RSNE_INFO 0x10
+#define RSN_MLO_LINK_KDE_LI_RSNXE_INFO 0x20
+#define RSN_MLO_LINK_KDE_LINK_MAC_INDEX 1
+
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
@@ -564,7 +611,6 @@
const u8 *gtk;
size_t gtk_len;
const u8 *mac_addr;
- size_t mac_addr_len;
const u8 *igtk;
size_t igtk_len;
const u8 *bigtk;
@@ -608,6 +654,19 @@
u16 aid;
const u8 *wmm;
size_t wmm_len;
+#define MAX_NUM_MLO_LINKS 15
+ u16 valid_mlo_gtks; /* bitmap of valid link GTK KDEs */
+ const u8 *mlo_gtk[MAX_NUM_MLO_LINKS];
+ size_t mlo_gtk_len[MAX_NUM_MLO_LINKS];
+ u16 valid_mlo_igtks; /* bitmap of valid link IGTK KDEs */
+ const u8 *mlo_igtk[MAX_NUM_MLO_LINKS];
+ size_t mlo_igtk_len[MAX_NUM_MLO_LINKS];
+ u16 valid_mlo_bigtks; /* bitmap of valid link BIGTK KDEs */
+ const u8 *mlo_bigtk[MAX_NUM_MLO_LINKS];
+ size_t mlo_bigtk_len[MAX_NUM_MLO_LINKS];
+ u16 valid_mlo_links; /* bitmap of valid MLO link KDEs */
+ const u8 *mlo_link[MAX_NUM_MLO_LINKS];
+ size_t mlo_link_len[MAX_NUM_MLO_LINKS];
};
int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
@@ -651,6 +710,8 @@
const u8 *data, size_t data_len,
const u8 *frame, size_t frame_len, u8 *mic);
+int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher);
+
int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
u8 *hash);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 055bf73..ba54da5 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -92,6 +92,15 @@
#define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH "
/** Channel switch (followed by freq=<MHz> and other channel parameters) */
#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
+/** MLO link channel switch started (followed by freq=<MHz> and other channel
+ * parameters)
+ */
+#define WPA_EVENT_LINK_CHANNEL_SWITCH_STARTED \
+ "CTRL-EVENT-STARTED-LINK-CHANNEL-SWITCH "
+/** MLO link channel switch (followed by freq=<MHz> and other channel
+ * parameters)
+ */
+#define WPA_EVENT_LINK_CHANNEL_SWITCH "CTRL-EVENT-LINK-CHANNEL-SWITCH "
/** SAE authentication failed due to unknown password identifier */
#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
@@ -213,6 +222,9 @@
#define DPP_EVENT_CSR "DPP-CSR "
#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED "
+#define DPP_EVENT_PB_STATUS "DPP-PB-STATUS "
+#define DPP_EVENT_PB_RESULT "DPP-PB-RESULT "
+#define DPP_EVENT_RELAY_NEEDS_CONTROLLER "DPP-RELAY-NEEDS-CONTROLLER "
/* MESH events */
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e4f3eb3..91df607 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1011,6 +1011,16 @@
struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
/**
+ * crypto_ec_key_set_priv - Initialize EC key pair from raw key data
+ * @group: Identifying number for the ECC group
+ * @raw: Raw key data
+ * @raw_len: Length of @raw buffer
+ * Returns: EC key or %NULL on failure
+ */
+struct crypto_ec_key * crypto_ec_key_set_priv(int group,
+ const u8 *raw, size_t raw_len);
+
+/**
* crypto_ec_key_parse_pub - Initialize EC key pair from SubjectPublicKeyInfo ASN.1
* @der: DER encoding of ASN.1 SubjectPublicKeyInfo
* @der_len: Length of @der buffer
@@ -1086,16 +1096,20 @@
* crypto_ec_key_get_public_key - Get EC public key as an EC point
* @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
* Returns: Public key as an EC point or %NULL on failure
+ *
+ * The caller needs to free the returned value with crypto_ec_point_deinit().
*/
-const struct crypto_ec_point *
+struct crypto_ec_point *
crypto_ec_key_get_public_key(struct crypto_ec_key *key);
/**
* crypto_ec_key_get_private_key - Get EC private key as a bignum
* @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
* Returns: Private key as a bignum or %NULL on failure
+ *
+ * The caller needs to free the returned value with crypto_bignum_deinit().
*/
-const struct crypto_bignum *
+struct crypto_bignum *
crypto_ec_key_get_private_key(struct crypto_ec_key *key);
/**
@@ -1309,6 +1323,58 @@
*/
void crypto_rsa_key_free(struct crypto_rsa_key *key);
+enum hpke_mode {
+ HPKE_MODE_BASE = 0x00,
+ HPKE_MODE_PSK = 0x01,
+ HPKE_MODE_AUTH = 0x02,
+ HPKE_MODE_AUTH_PSK = 0x03,
+};
+
+enum hpke_kem_id {
+ HPKE_DHKEM_P256_HKDF_SHA256 = 0x0010,
+ HPKE_DHKEM_P384_HKDF_SHA384 = 0x0011,
+ HPKE_DHKEM_P521_HKDF_SHA512 = 0x0012,
+ HPKE_DHKEM_X5519_HKDF_SHA256 = 0x0020,
+ HPKE_DHKEM_X448_HKDF_SHA512 = 0x0021,
+};
+
+enum hpke_kdf_id {
+ HPKE_KDF_HKDF_SHA256 = 0x0001,
+ HPKE_KDF_HKDF_SHA384 = 0x0002,
+ HPKE_KDF_HKDF_SHA512 = 0x0003,
+};
+
+enum hpke_aead_id {
+ HPKE_AEAD_AES_128_GCM = 0x0001,
+ HPKE_AEAD_AES_256_GCM = 0x0002,
+ HPKE_AEAD_CHACHA20POLY1305 = 0x0003,
+};
+
+/**
+ * hpke_base_seal - HPKE base mode single-shot encrypt
+ * Returns: enc | ct; or %NULL on failure
+ */
+struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id,
+ enum hpke_kdf_id kdf_id,
+ enum hpke_aead_id aead_id,
+ struct crypto_ec_key *peer_pub,
+ const u8 *info, size_t info_len,
+ const u8 *aad, size_t aad_len,
+ const u8 *pt, size_t pt_len);
+
+/**
+ * hpke_base_open - HPKE base mode single-shot decrypt
+ * @enc_ct: enc | ct
+ * Returns: pt; or %NULL on failure
+ */
+struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id,
+ enum hpke_kdf_id kdf_id,
+ enum hpke_aead_id aead_id,
+ struct crypto_ec_key *own_priv,
+ const u8 *info, size_t info_len,
+ const u8 *aad, size_t aad_len,
+ const u8 *enc_ct, size_t enc_ct_len);
+
/**
* crypto_unload - Unload crypto resources
*
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index fafb688..4147f41 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -2190,6 +2190,285 @@
}
+#ifdef CONFIG_DPP3
+
+static const struct hpke_test {
+ const char *name;
+ enum hpke_mode mode;
+ enum hpke_kem_id kem_id;
+ enum hpke_kdf_id kdf_id;
+ enum hpke_aead_id aead_id;
+ const char *info;
+ int sk_r_group;
+ const char *pk_r;
+ const char *sk_r;
+ const char *enc;
+ const char *pt;
+ const char *aad;
+ const char *ct;
+} hpke_tests[] = {
+ {
+ .name = "A.3. DHKEM(P-256, HKDF-SHA256), HKDF-SHA256, AES-128-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P256_HKDF_SHA256,
+ .kdf_id = HPKE_KDF_HKDF_SHA256,
+ .aead_id = HPKE_AEAD_AES_128_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 19,
+ .pk_r = "04fe8c19ce0905191ebc298a9245792531f26f0cece2460639e8bc39cb7f706a826a779b4cf969b8a0e539c7f62fb3d30ad6aa8f80e30f1d128aafd68a2ce72ea0",
+ .sk_r = "f3ce7fdae57e1a310d87f1ebbde6f328be0a99cdbcadf4d6589cf29de4b8ffd2",
+ .enc = "04a92719c6195d5085104f469a8b9814d5838ff72b60501e2c4466e5e67b325ac98536d7b61a1af4b78e5b7f951c0900be863c403ce65c9bfcb9382657222d18c4",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "5ad590bb8baa577f8619db35a36311226a896e7342a6d836d8b7bcd2f20b6c7f9076ac232e3ab2523f39513434",
+ },
+ {
+ .name = "A.4. DHKEM(P-256, HKDF-SHA256), HKDF-SHA512, AES-128-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P256_HKDF_SHA256,
+ .kdf_id = HPKE_KDF_HKDF_SHA512,
+ .aead_id = HPKE_AEAD_AES_128_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 19,
+ .pk_r = "04085aa5b665dc3826f9650ccbcc471be268c8ada866422f739e2d531d4a8818a9466bc6b449357096232919ec4fe9070ccbac4aac30f4a1a53efcf7af90610edd",
+ .sk_r = "3ac8530ad1b01885960fab38cf3cdc4f7aef121eaa239f222623614b4079fb38",
+ .enc = "0493ed86735bdfb978cc055c98b45695ad7ce61ce748f4dd63c525a3b8d53a15565c6897888070070c1579db1f86aaa56deb8297e64db7e8924e72866f9a472580",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "d3cf4984931484a080f74c1bb2a6782700dc1fef9abe8442e44a6f09044c88907200b332003543754eb51917ba",
+ },
+ {
+ .name = "A.6. DHKEM(P-521, HKDF-SHA512), HKDF-SHA512, AES-256-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P521_HKDF_SHA512,
+ .kdf_id = HPKE_KDF_HKDF_SHA512,
+ .aead_id = HPKE_AEAD_AES_256_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 21,
+ .pk_r = "0401b45498c1714e2dce167d3caf162e45e0642afc7ed435df7902ccae0e84ba0f7d373f646b7738bbbdca11ed91bdeae3cdcba3301f2457be452f271fa6837580e661012af49583a62e48d44bed350c7118c0d8dc861c238c72a2bda17f64704f464b57338e7f40b60959480c0e58e6559b190d81663ed816e523b6b6a418f66d2451ec64",
+ .sk_r = "01462680369ae375e4b3791070a7458ed527842f6a98a79ff5e0d4cbde83c27196a3916956655523a6a2556a7af62c5cadabe2ef9da3760bb21e005202f7b2462847",
+ .enc = "040138b385ca16bb0d5fa0c0665fbbd7e69e3ee29f63991d3e9b5fa740aab8900aaeed46ed73a49055758425a0ce36507c54b29cc5b85a5cee6bae0cf1c21f2731ece2013dc3fb7c8d21654bb161b463962ca19e8c654ff24c94dd2898de12051f1ed0692237fb02b2f8d1dc1c73e9b366b529eb436e98a996ee522aef863dd5739d2f29b0",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "170f8beddfe949b75ef9c387e201baf4132fa7374593dfafa90768788b7b2b200aafcc6d80ea4c795a7c5b841a",
+ },
+ { /* self-generated test vector for P-384 */
+ .name = "custom DHKEM(P-384, HKDF-SHA384), HKDF-SHA384, AES-256-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P384_HKDF_SHA384,
+ .kdf_id = HPKE_KDF_HKDF_SHA384,
+ .aead_id = HPKE_AEAD_AES_256_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 20,
+ .pk_r = "049c0e4dcbbb3c80715cafaa1839d0bc3c3adcc95eb8062f84175f9c3cec115e6b799061c65a0605907785c25b3571564706a8ba6a204452b38c7c205db17d328f2353df05d5f1c568e7503331178c36c2d37bbed48401295407face3f8dae5ed8",
+ .sk_r = "cabffb07d20ffcfdaa043e1de49e1654659e0f0aba5de56523e8b73dc80c579a9e5c89ed3810ec21c4bafcf74ad2a245",
+ .enc = "04b30bea96d0e51582033b02a4d676d0464a5eb2d858be86cda1c4e6f8b2aa9fb80f5365483f781b1b3a8b3b8efd50b0f7bca16f06d0435fa3da1d671ea0a318b40fe170a074923c651e5dc824966b7b98d0e36bdf932875dae7130369a793cecc",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "ae7feccfea0f8fcd620d15369a28db8701cdc90d55c20efff6296bd441697b0da34671d1f3c4864183e86d27fc",
+ },
+ { /* self-generated test vector for BP-256 */
+ .name = "custom PB-256 using DHKEM(P-256, HKDF-SHA256), HKDF-SHA256, AES-128-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P256_HKDF_SHA256,
+ .kdf_id = HPKE_KDF_HKDF_SHA256,
+ .aead_id = HPKE_AEAD_AES_128_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 28,
+ .pk_r = "04a2cb9c4cae90cdc1c27516e9f84b6b166e4b1dcc517286268239ddb0bf74cca6390fed092ac4423ab2192b8bb41a4824d908d2053b93fc813830bebac5ce19b9",
+ .sk_r = "11d9db41c4341166ca52f5a1775595c0bdb4934350daeb7bce659c4b7a40e314",
+ .enc = "047a25e309c7ee50ec27f13d44734a3ccd8c703e3affcc728513df416511ef9bf02f5e7750e7415de8b5f306ebd3fc88ea9b9368523eb1733a8d82c1a877e5a0f4",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "17c84b3f07f6ffe08ff2be45c709ea782229504aa5b2253876725c6c39f8d8c992304fc5877994f79d6c10d462",
+ },
+ { /* self-generated test vector for BP-384 */
+ .name = "custom PB-384 using DHKEM(P-384, HKDF-SHA384), HKDF-SHA384, AES-256-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P384_HKDF_SHA384,
+ .kdf_id = HPKE_KDF_HKDF_SHA384,
+ .aead_id = HPKE_AEAD_AES_256_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 29,
+ .pk_r = "041f4199ad28835908079c45d165d55630098be53eb4beede9921f5b2204fa396111f99ac54c56411f7cb2c43ec18d8e604d895027228cf975f5a4b598f189d8fb03e3fefe020258c40d4d1b15fd7587d209925d67a41f9659a8ed6f662fb441e4",
+ .sk_r = "7017cf8a5a9a81ad4e0d755ccbea27a378b787561f8d5662639850805fefcbaab6b9a15729872abb7dc53d19a6cf77e4",
+ .enc = "0415d49dedc5bc1ffe9f8de9022c266bb605ec6cd7b77b6ce68974095398856f8aefa4b7abbfbd496b99a2dda3a9c65f1a71b9d40255aa1c7c4205a8b4ef611b96ed29fd2d7b0cde4c0e82058805e6276025cc4fc606f6e5771c31bd9704e9ba0b",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "5f5e9f82bedadec0e9b01a1b304cb48b05c0d6d397b1c8a95ed541218ec54f634a41cbc4066910a409e47b254e",
+ },
+ { /* self-generated test vector for BP-512 */
+ .name = "custom PB-512 using DHKEM(P-521, HKDF-SHA512), HKDF-SHA512, AES-256-GCM",
+ .mode = HPKE_MODE_BASE,
+ .kem_id = HPKE_DHKEM_P521_HKDF_SHA512,
+ .kdf_id = HPKE_KDF_HKDF_SHA512,
+ .aead_id = HPKE_AEAD_AES_256_GCM,
+ .info = "4f6465206f6e2061204772656369616e2055726e",
+ .sk_r_group = 30,
+ .pk_r = "049e81046a531365a3b5215ac37e7b38f5fa34f86c4eb2e03113b197390a26c555bb007596e131c2541f336eb24a45f44283b5b53fedddfa5642675602fdec17d34120a35efffb44952e32dee7732f2f3245c3314269996b610703a63fb8555a75ca5092690a1125ae8712c1e31fd77aee42bd052e71f9f9459814d6f4065bcea0",
+ .sk_r = "483b6882608182b296843fa7dfffbdd61ed0372574d4aa32a035c8e33a493927aaf00d42bd9124ebe4df26010b38124668c02b35a749e74845d565734310cfe9",
+ .enc = "04158d18473aeb3b283d3345b1a87d3de2b192ff9e41b5a98f91daacfb24be72e698cbc04c33078681e507bf346c0ea70c927083a22ca9ea027f420067ee42285b798d95fea51002d097ce28371883202bfd300fb64943669e32c6f1a348087368bb480b757892ebd199a9389978c92cbc44076626d705a771fbbd90c030a6767e",
+ .pt = "4265617574792069732074727574682c20747275746820626561757479",
+ .aad = "436f756e742d30",
+ .ct = "033d91c4514857da5b833635180c1acc09f175cbf44777a7b71e177705cfd17437b1c85d671dd767bb4fe20e2e",
+ },
+};
+
+
+static int run_hpke_test(const struct hpke_test *test)
+{
+ struct wpabuf *info, *pk_r, *sk_r, *enc, *pt, *aad, *ct;
+ struct wpabuf *res_pt = NULL, *enc_ct = NULL, *res_ct = NULL;
+ struct crypto_ec_key *own_priv = NULL, *peer_pub = NULL;
+ int res = -1;
+ size_t coord_len;
+
+ wpa_printf(MSG_INFO, "- %s", test->name);
+
+ info = wpabuf_parse_bin(test->info);
+ pk_r = wpabuf_parse_bin(test->pk_r);
+ sk_r = wpabuf_parse_bin(test->sk_r);
+ enc = wpabuf_parse_bin(test->enc);
+ pt = wpabuf_parse_bin(test->pt);
+ aad = wpabuf_parse_bin(test->aad);
+ ct = wpabuf_parse_bin(test->ct);
+ if (!info || !pk_r || !sk_r || !enc || !pt || !aad || !ct) {
+ wpa_printf(MSG_ERROR, "Could not parse test data");
+ goto fail;
+ }
+
+ /* Receiver - decryption against the test vector */
+
+ enc_ct = wpabuf_concat(enc, ct);
+ enc = NULL;
+ ct = NULL;
+ if (!enc_ct)
+ goto fail;
+
+ own_priv = crypto_ec_key_set_priv(test->sk_r_group, wpabuf_head(sk_r),
+ wpabuf_len(sk_r));
+ if (!own_priv) {
+ wpa_printf(MSG_ERROR,
+ "HPKE base open - failed to set private key");
+ goto fail;
+ }
+
+ res_pt = hpke_base_open(test->kem_id, test->kdf_id, test->aead_id,
+ own_priv,
+ wpabuf_head(info), wpabuf_len(info),
+ wpabuf_head(aad), wpabuf_len(aad),
+ wpabuf_head(enc_ct), wpabuf_len(enc_ct));
+ if (!res_pt) {
+ wpa_printf(MSG_ERROR, "HPKE base open - failed to decrypt");
+ wpa_hexdump_buf(MSG_INFO, "pt", res_pt);
+ goto fail;
+ }
+ if (wpabuf_len(res_pt) != wpabuf_len(pt) ||
+ os_memcmp(wpabuf_head(res_pt), wpabuf_head(pt),
+ wpabuf_len(pt)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "HPKE base open - failed - decryption mismatch");
+ goto fail;
+ }
+
+ /* Sender - encryption (randomized algorithm) */
+
+ if (test->sk_r_group == 19)
+ coord_len = 32;
+ else if (test->sk_r_group == 20)
+ coord_len = 48;
+ else if (test->sk_r_group == 21)
+ coord_len = 66;
+ else if (test->sk_r_group == 28)
+ coord_len = 32;
+ else if (test->sk_r_group == 29)
+ coord_len = 48;
+ else if (test->sk_r_group == 30)
+ coord_len = 64;
+ else
+ goto fail;
+ if (wpabuf_len(pk_r) != 1 + 2 * coord_len) {
+ wpa_printf(MSG_ERROR, "Unexpected pkR length (%zu != %zu)",
+ wpabuf_len(pk_r), 1 + 2 * coord_len);
+ goto fail;
+ }
+ peer_pub = crypto_ec_key_set_pub(test->sk_r_group,
+ wpabuf_head_u8(pk_r) + 1,
+ wpabuf_head_u8(pk_r) + 1 + coord_len,
+ coord_len);
+ if (!peer_pub) {
+ wpa_printf(MSG_ERROR,
+ "HPKE base open - failed to set public key");
+ goto fail;
+ }
+
+ res_ct = hpke_base_seal(test->kem_id, test->kdf_id, test->aead_id,
+ peer_pub,
+ wpabuf_head(info), wpabuf_len(info),
+ wpabuf_head(aad), wpabuf_len(aad),
+ wpabuf_head(pt), wpabuf_len(pt));
+ if (!res_ct) {
+ wpa_printf(MSG_ERROR, "HPKE base open - failed to encrypt");
+ goto fail;
+ }
+
+ /* Receiver - decryption (to verify own encryption) */
+
+ wpabuf_free(res_pt);
+ res_pt = hpke_base_open(test->kem_id, test->kdf_id, test->aead_id,
+ own_priv,
+ wpabuf_head(info), wpabuf_len(info),
+ wpabuf_head(aad), wpabuf_len(aad),
+ wpabuf_head(res_ct), wpabuf_len(res_ct));
+ if (!res_pt) {
+ wpa_printf(MSG_ERROR, "HPKE base open - failed to decrypt own encrypted version");
+ goto fail;
+ }
+ if (wpabuf_len(res_pt) != wpabuf_len(pt) ||
+ os_memcmp(wpabuf_head(res_pt), wpabuf_head(pt),
+ wpabuf_len(pt)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "HPKE base open - failed - decryption mismatch for own encrypted version");
+ wpa_hexdump_buf(MSG_INFO, "pt", res_pt);
+ goto fail;
+ }
+
+ res = 0;
+fail:
+ wpabuf_free(info);
+ wpabuf_free(pk_r);
+ wpabuf_free(sk_r);
+ wpabuf_free(enc);
+ wpabuf_free(pt);
+ wpabuf_free(aad);
+ wpabuf_free(ct);
+ wpabuf_free(enc_ct);
+ wpabuf_free(res_pt);
+ wpabuf_free(res_ct);
+ crypto_ec_key_deinit(own_priv);
+ return res;
+}
+
+#endif /* CONFIG_DPP3 */
+
+
+static int test_hpke(void)
+{
+#ifdef CONFIG_DPP3
+ unsigned int i;
+
+ wpa_printf(MSG_INFO, "RFC 9180 - HPKE");
+ for (i = 0; i < ARRAY_SIZE(hpke_tests); i++) {
+ if (run_hpke_test(&hpke_tests[i]) < 0)
+ return -1;
+ }
+
+ wpa_printf(MSG_INFO, "HPKE base open test cases passed");
+#endif /* CONFIG_DPP3 */
+ return 0;
+}
+
+
static int test_ms_funcs(void)
{
#ifndef CONFIG_FIPS
@@ -2310,6 +2589,7 @@
test_sha384() ||
test_fips186_2_prf() ||
test_extract_expand_hkdf() ||
+ test_hpke() ||
test_ms_funcs())
ret = -1;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index c6e065f..f058e06 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -16,6 +16,7 @@
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
+#include <openssl/rsa.h>
#include <openssl/pem.h>
#ifdef CONFIG_ECC
#include <openssl/ec.h>
@@ -25,6 +26,8 @@
#include <openssl/provider.h>
#include <openssl/core_names.h>
#include <openssl/param_build.h>
+#include <openssl/encoder.h>
+#include <openssl/decoder.h>
#else /* OpenSSL version >= 3.0 */
#include <openssl/cmac.h>
#endif /* OpenSSL version >= 3.0 */
@@ -117,6 +120,19 @@
{
return ASN1_STRING_data((ASN1_STRING *) x);
}
+
+
+static const ASN1_TIME * X509_get0_notBefore(const X509 *x)
+{
+ return X509_get_notBefore(x);
+}
+
+
+static const ASN1_TIME * X509_get0_notAfter(const X509 *x)
+{
+ return X509_get_notAfter(x);
+}
+
#endif /* OpenSSL version < 1.1.0 */
@@ -1347,21 +1363,22 @@
ctx = os_zalloc(sizeof(*ctx));
if (!ctx)
- return NULL;
+ goto fail;
ctx->ctx = EVP_MAC_CTX_new(mac);
if (!ctx->ctx) {
- EVP_MAC_free(mac);
os_free(ctx);
- return NULL;
+ ctx = NULL;
+ goto fail;
}
if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) {
EVP_MAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
- EVP_MAC_free(mac);
- return NULL;
+ ctx = NULL;
+ goto fail;
}
+fail:
EVP_MAC_free(mac);
return ctx;
#else /* OpenSSL version >= 3.0 */
@@ -2216,6 +2233,7 @@
struct crypto_ec {
EC_GROUP *group;
int nid;
+ int iana_group;
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
@@ -2260,6 +2278,44 @@
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static const char * crypto_ec_group_2_name(int group)
+{
+ /* Map from IANA registry for IKE D-H groups to OpenSSL group name */
+ switch (group) {
+ case 19:
+ return "prime256v1";
+ case 20:
+ return "secp384r1";
+ case 21:
+ return "secp521r1";
+ case 25:
+ return "prime192v1";
+ case 26:
+ return "secp224r1";
+#ifdef NID_brainpoolP224r1
+ case 27:
+ return "brainpoolP224r1";
+#endif /* NID_brainpoolP224r1 */
+#ifdef NID_brainpoolP256r1
+ case 28:
+ return "brainpoolP256r1";
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+ case 29:
+ return "brainpoolP384r1";
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+ case 30:
+ return "brainpoolP512r1";
+#endif /* NID_brainpoolP512r1 */
+ default:
+ return NULL;
+ }
+}
+#endif /* OpenSSL version >= 3.0 */
+
+
struct crypto_ec * crypto_ec_init(int group)
{
struct crypto_ec *e;
@@ -2274,6 +2330,7 @@
return NULL;
e->nid = nid;
+ e->iana_group = group;
e->bnctx = BN_CTX_new();
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
@@ -2936,6 +2993,27 @@
struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = NULL;
+ OSSL_DECODER_CTX *ctx;
+
+ ctx = OSSL_DECODER_CTX_new_for_pkey(
+ &pkey, "DER", NULL, "EC",
+ OSSL_KEYMGMT_SELECT_KEYPAIR |
+ OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
+ NULL, NULL);
+ if (!ctx ||
+ OSSL_DECODER_from_data(ctx, &der, &der_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: Decoding EC private key (DER) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ return (struct crypto_ec_key *) pkey;
+fail:
+ crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
+ return NULL;
+#else /* OpenSSL version >= 3.0 */
EVP_PKEY *pkey = NULL;
EC_KEY *eckey;
@@ -2957,6 +3035,142 @@
fail:
crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
return NULL;
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
+struct crypto_ec_key * crypto_ec_key_set_priv(int group,
+ const u8 *raw, size_t raw_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ const char *group_name;
+ OSSL_PARAM params[4];
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL;
+ BIGNUM *priv;
+ EC_POINT *pub = NULL;
+ EC_GROUP *ec_group = NULL;
+ size_t len;
+ u8 *pub_bin = NULL;
+ u8 *priv_bin = NULL;
+ int priv_bin_len;
+
+ group_name = crypto_ec_group_2_name(group);
+ if (!group_name)
+ return NULL;
+
+ priv = BN_bin2bn(raw, raw_len, NULL);
+ if (!priv)
+ return NULL;
+ priv_bin = os_malloc(raw_len);
+ if (!priv_bin)
+ goto fail;
+ priv_bin_len = BN_bn2lebinpad(priv, priv_bin, raw_len);
+ if (priv_bin_len < 0)
+ goto fail;
+
+ ec_group = EC_GROUP_new_by_curve_name(crypto_ec_group_2_nid(group));
+ if (!ec_group)
+ goto fail;
+ pub = EC_POINT_new(ec_group);
+ if (!pub ||
+ EC_POINT_mul(ec_group, pub, priv, NULL, NULL, NULL) != 1)
+ goto fail;
+ len = EC_POINT_point2oct(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, NULL);
+ if (len == 0)
+ goto fail;
+ pub_bin = os_malloc(len);
+ if (!pub_bin)
+ goto fail;
+ len = EC_POINT_point2oct(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED,
+ pub_bin, len, NULL);
+ if (len == 0)
+ goto fail;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ (char *) group_name, 0);
+ params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY,
+ priv_bin, priv_bin_len);
+ params[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
+ pub_bin, len);
+ params[3] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+ if (!ctx ||
+ EVP_PKEY_fromdata_init(ctx) <= 0 ||
+ EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0)
+ goto fail;
+
+out:
+ bin_clear_free(priv_bin, raw_len);
+ os_free(pub_bin);
+ BN_clear_free(priv);
+ EVP_PKEY_CTX_free(ctx);
+ EC_POINT_free(pub);
+ EC_GROUP_free(ec_group);
+ return (struct crypto_ec_key *) pkey;
+
+fail:
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto out;
+#else /* OpenSSL version >= 3.0 */
+ EC_KEY *eckey = NULL;
+ EVP_PKEY *pkey = NULL;
+ BIGNUM *priv = NULL;
+ int nid;
+ const EC_GROUP *ec_group;
+ EC_POINT *pub = NULL;
+
+ nid = crypto_ec_group_2_nid(group);
+ if (nid < 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unsupported group %d", group);
+ return NULL;
+ }
+
+ eckey = EC_KEY_new_by_curve_name(nid);
+ priv = BN_bin2bn(raw, raw_len, NULL);
+ if (!eckey || !priv ||
+ EC_KEY_set_private_key(eckey, priv) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ ec_group = EC_KEY_get0_group(eckey);
+ if (!ec_group)
+ goto fail;
+ pub = EC_POINT_new(ec_group);
+ if (!pub ||
+ EC_POINT_mul(ec_group, pub, priv, NULL, NULL, NULL) != 1 ||
+ EC_KEY_set_public_key(eckey, pub) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set EC_KEY(pub): %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Could not create EVP_PKEY");
+ goto fail;
+ }
+
+out:
+ BN_clear_free(priv);
+ EC_POINT_free(pub);
+ return (struct crypto_ec_key *) pkey;
+
+fail:
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto out;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -2972,8 +3186,13 @@
}
/* Ensure this is an EC key */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (!EVP_PKEY_is_a(pkey, "EC"))
+ goto fail;
+#else /* OpenSSL version >= 3.0 */
if (!EVP_PKEY_get0_EC_KEY(pkey))
goto fail;
+#endif /* OpenSSL version >= 3.0 */
return (struct crypto_ec_key *) pkey;
fail:
crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
@@ -2984,6 +3203,47 @@
struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x,
const u8 *buf_y, size_t len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ const char *group_name;
+ OSSL_PARAM params[3];
+ u8 *pub;
+ EVP_PKEY_CTX *ctx;
+ EVP_PKEY *pkey = NULL;
+
+ group_name = crypto_ec_group_2_name(group);
+ if (!group_name)
+ return NULL;
+
+ pub = os_malloc(1 + len * 2);
+ if (!pub)
+ return NULL;
+ pub[0] = 0x04; /* uncompressed */
+ os_memcpy(pub + 1, buf_x, len);
+ os_memcpy(pub + 1 + len, buf_y, len);
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ (char *) group_name, 0);
+ params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
+ pub, 1 + len * 2);
+ params[2] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+ if (!ctx) {
+ os_free(pub);
+ return NULL;
+ }
+ if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
+ EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
+ os_free(pub);
+ EVP_PKEY_CTX_free(ctx);
+ return NULL;
+ }
+
+ os_free(pub);
+ EVP_PKEY_CTX_free(ctx);
+
+ return (struct crypto_ec_key *) pkey;
+#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey = NULL;
EVP_PKEY *pkey = NULL;
EC_GROUP *ec_group = NULL;
@@ -3058,6 +3318,7 @@
EVP_PKEY_free(pkey);
pkey = NULL;
goto out;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -3065,6 +3326,24 @@
crypto_ec_key_set_pub_point(struct crypto_ec *ec,
const struct crypto_ec_point *pub)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ int len = BN_num_bytes(ec->prime);
+ struct crypto_ec_key *key;
+ u8 *buf;
+
+ buf = os_malloc(2 * len);
+ if (!buf)
+ return NULL;
+ if (crypto_ec_point_to_bin(ec, pub, buf, buf + len) < 0) {
+ os_free(buf);
+ return NULL;
+ }
+
+ key = crypto_ec_key_set_pub(ec->iana_group, buf, buf + len, len);
+ os_free(buf);
+
+ return key;
+#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey;
EVP_PKEY *pkey = NULL;
@@ -3093,11 +3372,41 @@
EC_KEY_free(eckey);
pkey = NULL;
goto out;
+#endif /* OpenSSL version >= 3.0 */
}
struct crypto_ec_key * crypto_ec_key_gen(int group)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY_CTX *ctx;
+ OSSL_PARAM params[2];
+ const char *group_name;
+ EVP_PKEY *pkey = NULL;
+
+ group_name = crypto_ec_group_2_name(group);
+ if (!group_name)
+ return NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ (char *) group_name, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+ if (!ctx ||
+ EVP_PKEY_keygen_init(ctx) != 1 ||
+ EVP_PKEY_CTX_set_params(ctx, params) != 1 ||
+ EVP_PKEY_generate(ctx, &pkey) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: failed to generate EC keypair: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ pkey = NULL;
+ }
+
+ EVP_PKEY_CTX_free(ctx);
+
+ return (struct crypto_ec_key *) pkey;
+#else /* OpenSSL version >= 3.0 */
EVP_PKEY_CTX *kctx = NULL;
EC_KEY *ec_params = NULL, *eckey;
EVP_PKEY *params = NULL, *key = NULL;
@@ -3145,6 +3454,7 @@
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(kctx);
return (struct crypto_ec_key *) key;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -3183,6 +3493,54 @@
struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
{
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_ENCODER_CTX *ctx;
+ int selection;
+ unsigned char *pdata = NULL;
+ size_t pdata_len = 0;
+ EVP_PKEY *copy = NULL;
+ struct wpabuf *buf = NULL;
+
+ if (EVP_PKEY_get_ec_point_conv_form(pkey) !=
+ POINT_CONVERSION_COMPRESSED) {
+ copy = EVP_PKEY_dup(pkey);
+ if (!copy)
+ return NULL;
+ if (EVP_PKEY_set_utf8_string_param(
+ copy, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
+ OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED) !=
+ 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set compressed format");
+ EVP_PKEY_free(copy);
+ return NULL;
+ }
+ pkey = copy;
+ }
+
+ selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS |
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+
+ ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
+ "SubjectPublicKeyInfo",
+ NULL);
+ if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to encode SubjectPublicKeyInfo: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ pdata = NULL;
+ }
+ OSSL_ENCODER_CTX_free(ctx);
+ if (pdata) {
+ buf = wpabuf_alloc_copy(pdata, pdata_len);
+ OPENSSL_free(pdata);
+ }
+
+ EVP_PKEY_free(copy);
+
+ return buf;
+#else /* OpenSSL version >= 3.0 */
#ifdef OPENSSL_IS_BORINGSSL
unsigned char *der = NULL;
int der_len;
@@ -3196,7 +3554,7 @@
int nid;
ctx = BN_CTX_new();
- eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get0_EC_KEY(pkey);
if (!ctx || !eckey)
goto fail;
@@ -3249,33 +3607,16 @@
int der_len;
struct wpabuf *buf;
EC_KEY *eckey;
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- EVP_PKEY *tmp;
-#endif /* OpenSSL version >= 3.0 */
- eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (!eckey)
return NULL;
/* For now, all users expect COMPRESSED form */
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- tmp = EVP_PKEY_new();
- if (!tmp)
- return NULL;
- if (EVP_PKEY_set1_EC_KEY(tmp, eckey) != 1) {
- EVP_PKEY_free(tmp);
- return NULL;
- }
- key = (struct crypto_ec_key *) tmp;
-#endif /* OpenSSL version >= 3.0 */
-
der_len = i2d_PUBKEY((EVP_PKEY *) key, &der);
EC_KEY_free(eckey);
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- EVP_PKEY_free(tmp);
-#endif /* OpenSSL version >= 3.0 */
if (der_len <= 0) {
wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -3286,19 +3627,58 @@
OPENSSL_free(der);
return buf;
#endif /* OPENSSL_IS_BORINGSSL */
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
bool include_pub)
{
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_ENCODER_CTX *ctx;
+ int selection;
+ unsigned char *pdata = NULL;
+ size_t pdata_len = 0;
+ struct wpabuf *buf;
+ EVP_PKEY *copy = NULL;
+
+ selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS |
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+ if (include_pub) {
+ selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+ } else {
+ /* Not including OSSL_KEYMGMT_SELECT_PUBLIC_KEY does not seem
+ * to really be sufficient, so clone the key and explicitly
+ * mark it not to include the public key. */
+ copy = EVP_PKEY_dup(pkey);
+ if (!copy)
+ return NULL;
+ EVP_PKEY_set_int_param(copy, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC,
+ 0);
+ pkey = copy;
+ }
+
+ ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
+ "type-specific", NULL);
+ if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+ OSSL_ENCODER_CTX_free(ctx);
+ EVP_PKEY_free(copy);
+ return NULL;
+ }
+ OSSL_ENCODER_CTX_free(ctx);
+ buf = wpabuf_alloc_copy(pdata, pdata_len);
+ OPENSSL_free(pdata);
+ EVP_PKEY_free(copy);
+ return buf;
+#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey;
unsigned char *der = NULL;
int der_len;
struct wpabuf *buf;
unsigned int key_flags;
- eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (!eckey)
return NULL;
@@ -3319,18 +3699,53 @@
OPENSSL_free(der);
return buf;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
int prefix)
{
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct wpabuf *buf;
+ unsigned char *pos;
+ size_t pub_len = OSSL_PARAM_UNMODIFIED;
+
+ buf = NULL;
+ if (!EVP_PKEY_is_a(pkey, "EC") ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ NULL, 0, &pub_len) < 0 ||
+ pub_len == OSSL_PARAM_UNMODIFIED ||
+ !(buf = wpabuf_alloc(pub_len)) ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ wpabuf_put(buf, pub_len),
+ pub_len, NULL) != 1 ||
+ wpabuf_head_u8(buf)[0] != 0x04) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to get encoded public key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ if (!prefix) {
+ /* Remove 0x04 prefix if requested */
+ pos = wpabuf_mhead(buf);
+ os_memmove(pos, pos + 1, pub_len - 1);
+ buf->used--;
+ }
+
+ return buf;
+#else /* OpenSSL version >= 3.0 */
int len, res;
EC_KEY *eckey;
struct wpabuf *buf;
unsigned char *pos;
- eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (!eckey)
return NULL;
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
@@ -3367,30 +3782,92 @@
}
return buf;
+#endif /* OpenSSL version >= 3.0 */
}
-const struct crypto_ec_point *
+struct crypto_ec_point *
crypto_ec_key_get_public_key(struct crypto_ec_key *key)
{
- const EC_KEY *eckey;
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ char group[64];
+ unsigned char pub[256];
+ size_t len;
+ EC_POINT *point = NULL;
+ EC_GROUP *grp;
+ int res = 0;
+ OSSL_PARAM params[2];
- eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!EVP_PKEY_is_a(pkey, "EC") ||
+ EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME,
+ group, sizeof(group), &len) != 1 ||
+ EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
+ pub, sizeof(pub), &len) != 1)
+ return NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ group, 0);
+ params[1] = OSSL_PARAM_construct_end();
+ grp = EC_GROUP_new_from_params(params, NULL, NULL);
+ if (!grp)
+ goto fail;
+ point = EC_POINT_new(grp);
+ if (!point)
+ goto fail;
+ res = EC_POINT_oct2point(grp, point, pub, len, NULL);
+
+fail:
+ if (res != 1) {
+ EC_POINT_free(point);
+ point = NULL;
+ }
+
+ EC_GROUP_free(grp);
+
+ return (struct crypto_ec_point *) point;
+#else /* OpenSSL version >= 3.0 */
+ const EC_KEY *eckey;
+ const EC_POINT *point;
+ const EC_GROUP *group;
+
+ eckey = EVP_PKEY_get0_EC_KEY(pkey);
if (!eckey)
return NULL;
- return (const struct crypto_ec_point *) EC_KEY_get0_public_key(eckey);
+ group = EC_KEY_get0_group(eckey);
+ if (!group)
+ return NULL;
+ point = EC_KEY_get0_public_key(eckey);
+ if (!point)
+ return NULL;
+ return (struct crypto_ec_point *) EC_POINT_dup(point, group);
+#endif /* OpenSSL version >= 3.0 */
}
-const struct crypto_bignum *
+struct crypto_bignum *
crypto_ec_key_get_private_key(struct crypto_ec_key *key)
{
- const EC_KEY *eckey;
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ BIGNUM *bn = NULL;
- eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!EVP_PKEY_is_a(pkey, "EC") ||
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn) != 1)
+ return NULL;
+ return (struct crypto_bignum *) bn;
+#else /* OpenSSL version >= 3.0 */
+ const EC_KEY *eckey;
+ const BIGNUM *bn;
+
+ eckey = EVP_PKEY_get0_EC_KEY(pkey);
if (!eckey)
return NULL;
- return (const struct crypto_bignum *) EC_KEY_get0_private_key(eckey);
+ bn = EC_KEY_get0_private_key(eckey);
+ if (!bn)
+ return NULL;
+ return (struct crypto_bignum *) BN_dup(bn);
+#endif /* OpenSSL version >= 3.0 */
}
@@ -3943,6 +4420,8 @@
{
EVP_PKEY *pkey;
X509 *x509;
+ const ASN1_TIME *not_before, *not_after;
+ int res_before, res_after;
pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
if (pkey)
@@ -3953,17 +4432,36 @@
if (!x509)
return NULL;
+ not_before = X509_get0_notBefore(x509);
+ not_after = X509_get0_notAfter(x509);
+ if (!not_before || !not_after)
+ goto fail;
+ res_before = X509_cmp_current_time(not_before);
+ res_after = X509_cmp_current_time(not_after);
+ if (!res_before || !res_after)
+ goto fail;
+ if (res_before > 0 || res_after < 0) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Certificate for RSA public key is not valid at this time (%d %d)",
+ res_before, res_after);
+ goto fail;
+ }
+
pkey = X509_get_pubkey(x509);
X509_free(x509);
if (!pkey)
return NULL;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+ wpa_printf(MSG_INFO, "OpenSSL: No RSA public key found");
EVP_PKEY_free(pkey);
return NULL;
}
return pkey;
+fail:
+ X509_free(x509);
+ return NULL;
}
@@ -4068,6 +4566,769 @@
}
+#ifdef CONFIG_DPP3
+
+#define HPKE_MAX_SHARED_SECRET_LEN 66
+#define HPKE_MAX_HASH_LEN 64
+#define HPKE_MAX_KEY_LEN 32
+#define HPKE_MAX_NONCE_LEN 12
+#define HPKE_MAX_PUB_LEN (1 + 2 * 66)
+
+struct hpke_context {
+ /* KEM */
+ enum hpke_kem_id kem_id;
+ int kem_nid;
+ int iana_group;
+ size_t n_pk;
+ size_t n_secret;
+ const EVP_MD *kem_h;
+ size_t kem_n_h;
+
+ /* KDF */
+ enum hpke_kdf_id kdf_id;
+ const EVP_MD *kdf_h;
+ size_t n_h;
+
+ /* AEAD */
+ enum hpke_aead_id aead_id;
+ const EVP_CIPHER *cipher;
+ size_t n_k;
+ size_t n_n;
+ size_t n_t;
+ u8 key[HPKE_MAX_KEY_LEN];
+ u8 base_nonce[HPKE_MAX_NONCE_LEN];
+};
+
+
+static void hpke_free_context(struct hpke_context *ctx)
+{
+ bin_clear_free(ctx, sizeof(*ctx));
+}
+
+
+static struct hpke_context * hpke_get_context(enum hpke_kem_id kem_id,
+ enum hpke_kdf_id kdf_id,
+ enum hpke_aead_id aead_id,
+ struct crypto_ec_key *key)
+{
+ struct hpke_context *ctx;
+ int group;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ ctx->kem_id = kem_id;
+ switch (kem_id) {
+ case HPKE_DHKEM_P256_HKDF_SHA256:
+ ctx->kem_nid = NID_X9_62_prime256v1;
+ ctx->iana_group = 19;
+ ctx->n_pk = 65;
+ ctx->n_secret = 32;
+ ctx->kem_h = EVP_sha256();
+ ctx->kem_n_h = 32;
+ break;
+ case HPKE_DHKEM_P384_HKDF_SHA384:
+ ctx->kem_nid = NID_secp384r1;
+ ctx->iana_group = 20;
+ ctx->n_pk = 97;
+ ctx->n_secret = 48;
+ ctx->kem_h = EVP_sha384();
+ ctx->kem_n_h = 48;
+ break;
+ case HPKE_DHKEM_P521_HKDF_SHA512:
+ ctx->kem_nid = NID_secp521r1;
+ ctx->iana_group = 21;
+ ctx->n_pk = 133;
+ ctx->n_secret = 64;
+ ctx->kem_h = EVP_sha512();
+ ctx->kem_n_h = 64;
+ break;
+ default:
+ goto fail;
+ }
+
+ ctx->kdf_id = kdf_id;
+ switch (kdf_id) {
+ case HPKE_KDF_HKDF_SHA256:
+ ctx->kdf_h = EVP_sha256();
+ ctx->n_h = 32;
+ break;
+ case HPKE_KDF_HKDF_SHA384:
+ ctx->kdf_h = EVP_sha384();
+ ctx->n_h = 48;
+ break;
+ case HPKE_KDF_HKDF_SHA512:
+ ctx->kdf_h = EVP_sha512();
+ ctx->n_h = 64;
+ break;
+ default:
+ goto fail;
+ }
+
+ ctx->aead_id = aead_id;
+ switch (aead_id) {
+ case HPKE_AEAD_AES_128_GCM:
+ ctx->cipher = EVP_aes_128_gcm();
+ ctx->n_k = 16;
+ ctx->n_n = 12;
+ ctx->n_t = 16;
+ break;
+ case HPKE_AEAD_AES_256_GCM:
+ ctx->cipher = EVP_aes_256_gcm();
+ ctx->n_k = 32;
+ ctx->n_n = 12;
+ ctx->n_t = 16;
+ break;
+ default:
+ goto fail;
+ }
+
+ /* Convert BP-256/384/512 to P-256/384/521 for DPP */
+ group = crypto_ec_key_group(key);
+ if (group == 28 && ctx->iana_group == 19) {
+ ctx->iana_group = 28;
+ } else if (group == 29 && ctx->iana_group == 20) {
+ ctx->iana_group = 29;
+ } else if (group == 30 && ctx->iana_group == 21) {
+ ctx->iana_group = 30;
+ ctx->n_pk = 129;
+ }
+ if (group != ctx->iana_group) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:group mismatch (%d != %d)",
+ __func__, group, ctx->iana_group);
+ goto fail;
+ }
+
+ return ctx;
+fail:
+ hpke_free_context(ctx);
+ return NULL;
+}
+
+
+static size_t hpke_suite_id(struct hpke_context *ctx, bool kem, u8 *suite_id)
+{
+ size_t suite_id_len;
+
+ if (kem) {
+ os_memcpy(suite_id, "KEM", 3);
+ WPA_PUT_BE16(&suite_id[3], ctx->kem_id);
+ suite_id_len = 5;
+ } else {
+ os_memcpy(suite_id, "HPKE", 4);
+ WPA_PUT_BE16(&suite_id[4], ctx->kem_id);
+ WPA_PUT_BE16(&suite_id[6], ctx->kdf_id);
+ WPA_PUT_BE16(&suite_id[8], ctx->aead_id);
+ suite_id_len = 10;
+ }
+ return suite_id_len;
+}
+
+
+static int hpke_labeled_extract(struct hpke_context *ctx, bool kem,
+ const u8 *salt, size_t salt_len,
+ const char *label,
+ const u8 *ikm, size_t ikm_len, u8 *prk)
+{
+ u8 zero[HPKE_MAX_HASH_LEN];
+ u8 suite_id[10];
+ size_t suite_id_len;
+ unsigned int mdlen = kem ? ctx->kem_n_h : ctx->n_h;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC *hmac;
+ OSSL_PARAM params[2];
+ EVP_MAC_CTX *hctx;
+ size_t mlen;
+ int res;
+#else /* OpenSSL version >= 3.0 */
+ HMAC_CTX *hctx;
+ int res;
+#endif /* OpenSSL version >= 3.0 */
+
+ if (!salt || !salt_len) {
+ salt_len = mdlen;
+ os_memset(zero, 0, salt_len);
+ salt = zero;
+ }
+
+ suite_id_len = hpke_suite_id(ctx, kem, suite_id);
+
+ /* labeled_ikm = concat("HPKE-v1", suite_id, label, ikm)
+ * return Extract(salt, labeled_ikm) */
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!hmac)
+ return -1;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(
+ "digest",
+ (char *) EVP_MD_get0_name(kem ? ctx->kem_h : ctx->kdf_h), 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ hctx = EVP_MAC_CTX_new(hmac);
+ EVP_MAC_free(hmac);
+ if (!hctx)
+ return -1;
+
+ if (EVP_MAC_init(hctx, salt, salt_len, params) != 1)
+ goto fail;
+
+ if (EVP_MAC_update(hctx, (const unsigned char *) "HPKE-v1", 7) != 1 ||
+ EVP_MAC_update(hctx, suite_id, suite_id_len) != 1 ||
+ EVP_MAC_update(hctx, (const unsigned char *) label,
+ os_strlen(label)) != 1 ||
+ EVP_MAC_update(hctx, ikm, ikm_len) != 1)
+ goto fail;
+
+ res = EVP_MAC_final(hctx, prk, &mlen, mdlen);
+ EVP_MAC_CTX_free(hctx);
+
+ return res == 1 ? 0 : -1;
+fail:
+ EVP_MAC_CTX_free(hctx);
+ return -1;
+#else /* OpenSSL version >= 3.0 */
+ hctx = HMAC_CTX_new();
+ if (!hctx)
+ return -1;
+ res = HMAC_Init_ex(hctx, salt, salt_len, kem ? ctx->kem_h : ctx->kdf_h,
+ NULL);
+ if (res != 1)
+ goto done;
+
+ HMAC_Update(hctx, (const unsigned char *) "HPKE-v1", 7);
+ HMAC_Update(hctx, suite_id, suite_id_len);
+ HMAC_Update(hctx, (const unsigned char *) label, os_strlen(label));
+ HMAC_Update(hctx, ikm, ikm_len);
+
+ res = HMAC_Final(hctx, prk, &mdlen);
+done:
+ HMAC_CTX_free(hctx);
+
+ return res == 1 ? 0 : -1;
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
+static int
+hpke_labeled_expand(struct hpke_context *ctx, bool kem, const u8 *prk,
+ const char *label, const u8 *info, size_t info_len,
+ u8 *out, size_t out_len)
+{
+ u8 suite_id[10];
+ size_t suite_id_len;
+ u8 hash[HPKE_MAX_HASH_LEN];
+ u8 iter = 0;
+ size_t label_len = os_strlen(label);
+ u8 *pos;
+ size_t left = out_len, clen;
+ int res = -1;
+ u8 *labeled_info;
+ size_t labeled_info_len;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC *hmac;
+ OSSL_PARAM params[2];
+ EVP_MAC_CTX *hctx = NULL;
+ size_t mdlen;
+#else /* OpenSSL version >= 3.0 */
+ HMAC_CTX *hctx;
+ unsigned int mdlen;
+#endif /* OpenSSL version >= 3.0 */
+
+ /* labeled_info = concat(I2OSP(L, 2), "HPKE-v1", suite_id,
+ * label, info)
+ * return Expand(prk, labeled_info, L) */
+ suite_id_len = hpke_suite_id(ctx, kem, suite_id);
+ labeled_info_len = 2 + 7 + suite_id_len + label_len + info_len;
+ labeled_info = os_malloc(labeled_info_len);
+ if (!labeled_info)
+ return -1;
+ pos = labeled_info;
+ WPA_PUT_BE16(pos, out_len);
+ pos += 2;
+ os_memcpy(pos, "HPKE-v1", 7);
+ pos += 7;
+ os_memcpy(pos, suite_id, suite_id_len);
+ pos += suite_id_len;
+ os_memcpy(pos, label, label_len);
+ pos += label_len;
+ if (info && info_len) {
+ os_memcpy(pos, info, info_len);
+ pos += info_len;
+ }
+
+ pos = out;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!hmac)
+ return -1;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(
+ "digest",
+ (char *) EVP_MD_get0_name(kem ? ctx->kem_h : ctx->kdf_h), 0);
+ params[1] = OSSL_PARAM_construct_end();
+#else /* OpenSSL version >= 3.0 */
+ hctx = HMAC_CTX_new();
+ if (!hctx)
+ return -1;
+#endif /* OpenSSL version >= 3.0 */
+
+ while (left > 0) {
+ mdlen = kem ? ctx->kem_n_h : ctx->n_h;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX_free(hctx);
+ hctx = EVP_MAC_CTX_new(hmac);
+ if (!hctx)
+ return -1;
+
+ if (EVP_MAC_init(hctx, prk, mdlen, params) != 1)
+ goto fail;
+
+ if (iter > 0 && EVP_MAC_update(hctx, hash, mdlen) != 1)
+ goto fail;
+ if (iter == 255)
+ goto fail;
+ iter++;
+
+ if (EVP_MAC_update(hctx, labeled_info, labeled_info_len) != 1 ||
+ EVP_MAC_update(hctx, &iter, sizeof(iter)) != 1)
+ goto fail;
+
+ if (EVP_MAC_final(hctx, hash, &mdlen, mdlen) != 1)
+ goto fail;
+#else /* OpenSSL version >= 3.0 */
+ if (HMAC_Init_ex(hctx, prk, mdlen,
+ kem ? ctx->kem_h : ctx->kdf_h,
+ NULL) != 1)
+ goto fail;
+
+ if (iter > 0)
+ HMAC_Update(hctx, hash, mdlen);
+ if (iter == 255)
+ goto fail;
+ iter++;
+ HMAC_Update(hctx, labeled_info, labeled_info_len);
+ HMAC_Update(hctx, &iter, sizeof(iter));
+
+ if (HMAC_Final(hctx, hash, &mdlen) != 1)
+ goto fail;
+ HMAC_CTX_reset(hctx);
+#endif /* OpenSSL version >= 3.0 */
+
+ clen = left > mdlen ? mdlen : left;
+ os_memcpy(pos, hash, clen);
+ pos += clen;
+ left -= clen;
+ }
+ res = 0;
+fail:
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_free(hmac);
+ EVP_MAC_CTX_free(hctx);
+#else /* OpenSSL version >= 3.0 */
+ HMAC_CTX_free(hctx);
+#endif /* OpenSSL version >= 3.0 */
+ os_free(labeled_info);
+
+ return res;
+}
+
+
+static int hpke_extract_and_expand(struct hpke_context *ctx,
+ const u8 *dhss, size_t dhss_len,
+ const u8 *enc, size_t enc_len,
+ const u8 *pk_rm, size_t pk_rm_len,
+ u8 *shared_secret)
+{
+ u8 kem_context[2 * HPKE_MAX_PUB_LEN];
+ u8 eae_prk[HPKE_MAX_HASH_LEN];
+
+ /* eae_prk = LabeledExtract("", "eae_prk", dh) */
+ if (hpke_labeled_extract(ctx, true, NULL, 0, "eae_prk", dhss, dhss_len,
+ eae_prk) < 0)
+ return -1;
+
+ if (enc_len > HPKE_MAX_PUB_LEN || pk_rm_len > HPKE_MAX_PUB_LEN)
+ return -1;
+ /* kem_context = concat(enc, pkRm) */
+ os_memcpy(kem_context, enc, enc_len);
+ os_memcpy(&kem_context[enc_len], pk_rm, pk_rm_len);
+
+ /* shared_secret = LabeledExpand(eae_prk, "shared_secret",
+ * kem_context, Nsecret) */
+ if (hpke_labeled_expand(ctx, true, eae_prk, "shared_secret",
+ kem_context, enc_len + pk_rm_len,
+ shared_secret, ctx->n_secret) < 0)
+ return -1;
+
+ forced_memzero(eae_prk, sizeof(eae_prk));
+ return 0;
+}
+
+
+static int hpke_key_schedule(struct hpke_context *ctx, const u8 *shared_secret,
+ const u8 *info, size_t info_len)
+{
+ u8 key_schedule_context[1 + 2 * HPKE_MAX_HASH_LEN];
+ u8 secret[HPKE_MAX_HASH_LEN];
+ int res = -1;
+
+ /* key_schedule_context = concat(mode, psk_id_hash, info_hash) */
+ key_schedule_context[0] = HPKE_MODE_BASE;
+
+ /* psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id) */
+ if (hpke_labeled_extract(ctx, false, NULL, 0, "psk_id_hash",
+ NULL, 0, &key_schedule_context[1]) < 0)
+ goto fail;
+
+ /* info_hash = LabeledExtract("", "info_hash", info) */
+ if (hpke_labeled_extract(ctx, false, NULL, 0, "info_hash",
+ info, info_len,
+ &key_schedule_context[1 + ctx->n_h]) < 0)
+ goto fail;
+
+ /* secret = LabeledExtract(shared_secret, "secret", psk) */
+ if (hpke_labeled_extract(ctx, false, shared_secret, ctx->n_secret,
+ "secret", NULL, 0, secret) < 0)
+ goto fail;
+
+ /* key = LabeledExpand(secret, "key", key_schedule_context, Nk) */
+ if (hpke_labeled_expand(ctx, false, secret, "key",
+ key_schedule_context, 1 + 2 * ctx->n_h,
+ ctx->key, ctx->n_k) < 0)
+ goto fail;
+
+ /* base_nonce = LabeledExpand(secret, "base_nonce",
+ * key_schedule_context, Nn) */
+ if (hpke_labeled_expand(ctx, false, secret, "base_nonce",
+ key_schedule_context, 1 + 2 * ctx->n_h,
+ ctx->base_nonce, ctx->n_n) < 0)
+ goto fail;
+ res = 0;
+fail:
+ forced_memzero(key_schedule_context, sizeof(key_schedule_context));
+ forced_memzero(secret, sizeof(secret));
+ return res;
+}
+
+
+static int hpke_encap(struct hpke_context *ctx, struct crypto_ec_key *pk_r,
+ u8 *shared_secret, u8 *enc)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ struct crypto_ec_key *sk_e;
+ int res = -1;
+ u8 dhss[HPKE_MAX_SHARED_SECRET_LEN + 16];
+ size_t dhss_len;
+ struct wpabuf *enc_buf = NULL, *pk_rm = NULL;
+
+ /* skE, pkE = GenerateKeyPair() */
+ sk_e = crypto_ec_key_gen(ctx->iana_group);
+ if (!sk_e) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:Could not generate key pair",
+ __func__);
+ goto fail;
+ }
+
+ /* dh = DH(skE, pkR) */
+ dhss_len = sizeof(dhss);
+ pctx = EVP_PKEY_CTX_new((EVP_PKEY *) sk_e, NULL);
+ if (!pctx ||
+ EVP_PKEY_derive_init(pctx) != 1 ||
+ EVP_PKEY_derive_set_peer(pctx, (EVP_PKEY *) pk_r) != 1 ||
+ EVP_PKEY_derive(pctx, dhss, &dhss_len) != 1 ||
+ dhss_len > HPKE_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ /* enc = SerializePublicKey(pkE) */
+ enc_buf = crypto_ec_key_get_pubkey_point(sk_e, 1);
+ if (!enc_buf)
+ goto fail;
+ os_memcpy(enc, wpabuf_head(enc_buf), wpabuf_len(enc_buf));
+
+ /* pkRm = SerializePublicKey(pkR) */
+ pk_rm = crypto_ec_key_get_pubkey_point(pk_r, 1);
+ if (!pk_rm)
+ goto fail;
+
+ /* kem_context = concat(enc, pkRm) */
+ /* shared_secret = ExtractAndExpand(dh, kem_context) */
+ /* return shared_secret, enc */
+ res = hpke_extract_and_expand(ctx, dhss, dhss_len, enc, ctx->n_pk,
+ wpabuf_head(pk_rm),
+ wpabuf_len(pk_rm), shared_secret);
+fail:
+ forced_memzero(dhss, sizeof(dhss));
+ crypto_ec_key_deinit(sk_e);
+ EVP_PKEY_CTX_free(pctx);
+ wpabuf_free(enc_buf);
+ wpabuf_free(pk_rm);
+ return res;
+}
+
+
+static struct wpabuf *
+hpke_aead_seal(struct hpke_context *ctx, const u8 *aad, size_t aad_len,
+ const u8 *pt, size_t pt_len)
+{
+ EVP_CIPHER_CTX *cctx;
+ int len = 0;
+ struct wpabuf *ct = NULL;
+
+ /* No need to xor in sequence number since we support only the
+ * single-shot API, i.e., base_nonce can be used as-is. */
+
+ cctx = EVP_CIPHER_CTX_new();
+ if (!cctx ||
+ EVP_EncryptInit_ex(cctx, ctx->cipher, NULL, ctx->key,
+ ctx->base_nonce) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptInit_ex failed",
+ __func__);
+ goto fail;
+ }
+ if (aad && aad_len &&
+ EVP_EncryptUpdate(cctx, NULL, &len, aad, aad_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_EncryptUpdate(AAD) failed",
+ __func__);
+ goto fail;
+ }
+ ct = wpabuf_alloc(pt_len + AES_BLOCK_SIZE + ctx->n_t);
+ if (!ct)
+ goto fail;
+ if (EVP_EncryptUpdate(cctx, wpabuf_put(ct, 0), &len, pt, pt_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_EncryptUpdate failed",
+ __func__);
+ goto fail;
+ }
+ wpabuf_put(ct, len);
+
+ if (EVP_EncryptFinal(cctx, wpabuf_put(ct, 0), &len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptFinal failed",
+ __func__);
+ wpabuf_free(ct);
+ ct = NULL;
+ goto fail;
+ }
+
+ if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG, ctx->n_t,
+ wpabuf_put(ct, ctx->n_t)) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:Could not get tag",
+ __func__);
+ wpabuf_free(ct);
+ ct = NULL;
+ goto fail;
+ }
+fail:
+ EVP_CIPHER_CTX_free(cctx);
+ return ct;
+}
+
+
+struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id,
+ enum hpke_kdf_id kdf_id,
+ enum hpke_aead_id aead_id,
+ struct crypto_ec_key *peer_pub,
+ const u8 *info, size_t info_len,
+ const u8 *aad, size_t aad_len,
+ const u8 *pt, size_t pt_len)
+{
+ struct hpke_context *ctx;
+ u8 shared_secret[HPKE_MAX_SHARED_SECRET_LEN];
+ u8 enc[1 + 2 * HPKE_MAX_PUB_LEN];
+ struct wpabuf *ct = NULL, *enc_ct = NULL;
+
+ ctx = hpke_get_context(kem_id, kdf_id, aead_id, peer_pub);
+ if (!ctx)
+ return NULL;
+
+ /* shared_secret, enc = Encap(pkR) */
+ if (hpke_encap(ctx, peer_pub, shared_secret, enc) < 0)
+ goto fail;
+
+ /* KeyScheduleS(mode_base, shared_secret, info,
+ * default_psk, default_psk_id) */
+ if (hpke_key_schedule(ctx, shared_secret, info, info_len) < 0)
+ goto fail;
+
+ /* ct = ctx.Seal(aad, pt) */
+ ct = hpke_aead_seal(ctx, aad, aad_len, pt, pt_len);
+ if (!ct)
+ goto fail;
+
+ /* return enc, ct */
+ enc_ct = wpabuf_alloc(ctx->n_pk + wpabuf_len(ct));
+ if (!enc_ct)
+ goto fail;
+ wpabuf_put_data(enc_ct, enc, ctx->n_pk);
+ wpabuf_put_buf(enc_ct, ct);
+
+fail:
+ forced_memzero(shared_secret, sizeof(shared_secret));
+ hpke_free_context(ctx);
+ wpabuf_free(ct);
+ return enc_ct;
+}
+
+
+static int hpke_decap(struct hpke_context *ctx, const u8 *enc,
+ size_t enc_ct_len, struct crypto_ec_key *sk_r,
+ u8 *shared_secret)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ struct wpabuf *pk_rm = NULL;
+ size_t len;
+ int res = -1;
+ struct crypto_ec_key *pk_e = NULL;
+ u8 dhss[HPKE_MAX_SHARED_SECRET_LEN + 16];
+ size_t dhss_len;
+
+ /* pkE = DeserializePublicKey(enc) */
+ if (enc_ct_len < ctx->n_pk)
+ return -1; /* not enough room for enc */
+ if (enc[0] != 0x04)
+ return -1; /* not in uncompressed form */
+ len = (ctx->n_pk - 1) / 2;
+ pk_e = crypto_ec_key_set_pub(ctx->iana_group, &enc[1],
+ &enc[1 + len], len);
+ if (!pk_e)
+ return -1; /* invalid public key point */
+ /* dh = DH(skR, pkE) */
+ dhss_len = sizeof(dhss);
+ pctx = EVP_PKEY_CTX_new((EVP_PKEY *) sk_r, NULL);
+ if (!pctx ||
+ EVP_PKEY_derive_init(pctx) != 1 ||
+ EVP_PKEY_derive_set_peer(pctx, (EVP_PKEY *) pk_e) != 1 ||
+ EVP_PKEY_derive(pctx, dhss, &dhss_len) != 1 ||
+ dhss_len > HPKE_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ /* pkRm = SerializePublicKey(pk(skR)) */
+ pk_rm = crypto_ec_key_get_pubkey_point(sk_r, 1);
+ if (!pk_rm)
+ goto fail;
+
+ /* kem_context = concat(enc, pkRm) */
+ /* shared_secret = ExtractAndExpand(dh, kem_context) */
+ res = hpke_extract_and_expand(ctx, dhss, dhss_len, enc, ctx->n_pk,
+ wpabuf_head(pk_rm),
+ wpabuf_len(pk_rm), shared_secret);
+fail:
+ forced_memzero(dhss, sizeof(dhss));
+ crypto_ec_key_deinit(pk_e);
+ EVP_PKEY_CTX_free(pctx);
+ wpabuf_free(pk_rm);
+ return res;
+}
+
+
+static struct wpabuf *
+hpke_aead_open(struct hpke_context *ctx, const u8 *aad, size_t aad_len,
+ const u8 *ct, size_t ct_len)
+{
+ EVP_CIPHER_CTX *cctx;
+ int len = 0;
+ const u8 *tag;
+ struct wpabuf *pt = NULL;
+
+ if (ct_len < ctx->n_t)
+ return NULL;
+ tag = ct + ct_len - ctx->n_t;
+ ct_len -= ctx->n_t;
+
+ /* No need to xor in sequence number since we support only the
+ * single-shot API, i.e., base_nonce can be used as-is. */
+
+ cctx = EVP_CIPHER_CTX_new();
+ if (!cctx ||
+ EVP_DecryptInit_ex(cctx, ctx->cipher, NULL, ctx->key,
+ ctx->base_nonce) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptInit_ex failed",
+ __func__);
+ goto fail;
+ }
+ if (aad && aad_len &&
+ EVP_DecryptUpdate(cctx, NULL, &len, aad, aad_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptUpdate(AAD) failed",
+ __func__);
+ goto fail;
+ }
+ pt = wpabuf_alloc(ct_len + AES_BLOCK_SIZE);
+ if (!pt)
+ goto fail;
+ if (EVP_DecryptUpdate(cctx, wpabuf_put(pt, 0), &len, ct, ct_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptUpdate failed",
+ __func__);
+ goto fail;
+ }
+ wpabuf_put(pt, len);
+
+ if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_TAG, ctx->n_t,
+ (void *) tag) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:Could not set tag",
+ __func__);
+ wpabuf_free(pt);
+ pt = NULL;
+ goto fail;
+ }
+
+ if (EVP_DecryptFinal(cctx, wpabuf_put(pt, 0), &len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptFinal failed",
+ __func__);
+ wpabuf_free(pt);
+ pt = NULL;
+ }
+fail:
+ EVP_CIPHER_CTX_free(cctx);
+ return pt;
+}
+
+
+struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id,
+ enum hpke_kdf_id kdf_id,
+ enum hpke_aead_id aead_id,
+ struct crypto_ec_key *own_priv,
+ const u8 *info, size_t info_len,
+ const u8 *aad, size_t aad_len,
+ const u8 *enc_ct, size_t enc_ct_len)
+{
+ struct hpke_context *ctx;
+ u8 shared_secret[HPKE_MAX_SHARED_SECRET_LEN];
+ struct wpabuf *pt = NULL;
+
+ ctx = hpke_get_context(kem_id, kdf_id, aead_id, own_priv);
+ if (!ctx)
+ return NULL;
+
+ /* shared_secret = Decap(enc, skR) */
+ if (hpke_decap(ctx, enc_ct, enc_ct_len, own_priv, shared_secret) < 0)
+ goto fail;
+
+ /* KeyScheduleR(mode_base, shared_secret, info,
+ * default_psk, default_psk_id) */
+ if (hpke_key_schedule(ctx, shared_secret, info, info_len) < 0)
+ goto fail;
+
+ /* return ctx.Open(aad, ct) */
+ pt = hpke_aead_open(ctx, aad, aad_len,
+ &enc_ct[ctx->n_pk], enc_ct_len - ctx->n_pk);
+
+fail:
+ forced_memzero(shared_secret, sizeof(shared_secret));
+ hpke_free_context(ctx);
+ return pt;
+}
+
+#endif /* CONFIG_DPP3 */
+
+
void crypto_unload(void)
{
openssl_unload_legacy_provider();
diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c
index a4bf50a..f9347d0 100644
--- a/src/crypto/fips_prf_internal.c
+++ b/src/crypto/fips_prf_internal.c
@@ -17,10 +17,11 @@
int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
u8 xkey[64];
- u32 t[5], _t[5];
+ u32 _t[5];
int i, j, m, k;
u8 *xpos = x;
u32 carry;
+ struct SHA1Context ctx;
if (seed_len < sizeof(xkey))
os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
@@ -30,11 +31,7 @@
/* FIPS 186-2 + change notice 1 */
os_memcpy(xkey, seed, seed_len);
- t[0] = 0x67452301;
- t[1] = 0xEFCDAB89;
- t[2] = 0x98BADCFE;
- t[3] = 0x10325476;
- t[4] = 0xC3D2E1F0;
+ SHA1Init(&ctx);
m = xlen / 40;
for (j = 0; j < m; j++) {
@@ -43,7 +40,7 @@
/* XVAL = (XKEY + XSEED_j) mod 2^b */
/* w_i = G(t, XVAL) */
- os_memcpy(_t, t, 20);
+ os_memcpy(_t, ctx.state, 20);
SHA1Transform(_t, xkey);
_t[0] = host_to_be32(_t[0]);
_t[1] = host_to_be32(_t[1]);
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index 4697e04..484f772 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -7,6 +7,19 @@
*/
#include "includes.h"
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+/* OpenSSL 3.0 has deprecated the low-level SHA1 functions and does not
+ * include an upper layer interface that could be used to use the
+ * SHA1_Transform() function. Use the internal SHA-1 implementation instead
+ * as a workaround. */
+#include "sha1-internal.c"
+#include "fips_prf_internal.c"
+
+#else /* OpenSSL version >= 3.0 */
+
#include <openssl/sha.h>
#include "common.h"
@@ -97,3 +110,5 @@
return 0;
}
+
+#endif /* OpenSSL version >= 3.0 */
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index a1b5166..dc8a1b4 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1584,6 +1584,15 @@
struct tls_connection *conn = arg;
const u8 *pos = buf;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if ((SSL_version(ssl) == TLS1_VERSION ||
+ SSL_version(ssl) == TLS1_1_VERSION) &&
+ SSL_get_security_level(ssl) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Drop security level to 0 to allow TLS 1.0/1.1 use of MD5-SHA1 signature algorithm");
+ SSL_set_security_level(ssl, 0);
+ }
+#endif /* OpenSSL version >= 3.0 */
if (write_p == 2) {
wpa_printf(MSG_DEBUG,
"OpenSSL: session ver=0x%x content_type=%d",
@@ -4180,8 +4189,10 @@
"TLS: Failed to decode domain parameters from '%s': %s",
dh_file, ERR_error_string(ERR_get_error(), NULL));
BIO_free(bio);
+ OSSL_DECODER_CTX_free(ctx);
return -1;
}
+ OSSL_DECODER_CTX_free(ctx);
BIO_free(bio);
if (!tmpkey) {
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 46cee44..6bbf1ec 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -66,6 +66,7 @@
HOSTAPD_CHAN_WIDTH_40M = BIT(3),
HOSTAPD_CHAN_WIDTH_80 = BIT(4),
HOSTAPD_CHAN_WIDTH_160 = BIT(5),
+ HOSTAPD_CHAN_WIDTH_320 = BIT(6),
};
/* Filter gratuitous ARP */
@@ -667,6 +668,16 @@
*/
unsigned int p2p_include_6ghz:1;
+ /**
+ * non_coloc_6ghz - Force scanning of non-PSC 6 GHz channels
+ *
+ * If this is set, the driver should scan non-PSC channels from the
+ * scan request even if neighbor reports from 2.4/5 GHz APs did not
+ * report a co-located AP on these channels. The default is to scan
+ * non-PSC channels only if a co-located AP was reported on the channel.
+ */
+ unsigned int non_coloc_6ghz:1;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -989,6 +1000,17 @@
unsigned int key_mgmt_suite;
/**
+ * allowed_key_mgmts - Bitfield of allowed key management suites
+ * (WPA_KEY_MGMT_*) other than @key_mgmt_suite for the current
+ * connection
+ *
+ * SME in the driver may choose key_mgmt from this list for the initial
+ * connection or roaming. The driver which doesn't support this
+ * ignores this parameter.
+ */
+ unsigned int allowed_key_mgmts;
+
+ /**
* auth_alg - Allowed authentication algorithms
* Bit field of WPA_AUTH_ALG_*
*/
@@ -1864,6 +1886,8 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384 0x00200000
#define WPA_DRIVER_CAPA_KEY_MGMT_CCKM 0x00400000
#define WPA_DRIVER_CAPA_KEY_MGMT_OSEN 0x00800000
+#define WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY 0x01000000
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY 0x02000000
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
unsigned int key_mgmt_iftype[WPA_IF_MAX];
@@ -2042,15 +2066,15 @@
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
/** Driver supports TX status reports for EAPOL frames through control port */
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS 0x0000000000000002ULL
-/** Driver supports secure LTF */
-#define WPA_DRIVER_FLAGS2_SEC_LTF 0x0000000000000004ULL
-/** Driver supports secure RTT measurement exchange */
-#define WPA_DRIVER_FLAGS2_SEC_RTT 0x0000000000000008ULL
+/** Driver supports secure LTF in AP mode */
+#define WPA_DRIVER_FLAGS2_SEC_LTF_AP 0x0000000000000004ULL
+/** Driver supports secure RTT measurement exchange in AP mode */
+#define WPA_DRIVER_FLAGS2_SEC_RTT_AP 0x0000000000000008ULL
/**
* Driver supports protection of range negotiation and measurement management
- * frames
+ * frames in AP mode
*/
-#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG 0x0000000000000010ULL
+#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP 0x0000000000000010ULL
/** Driver supports Beacon frame TX rate configuration (HE rates) */
#define WPA_DRIVER_FLAGS2_BEACON_RATE_HE 0x0000000000000020ULL
/** Driver supports Beacon protection only in client mode */
@@ -2063,6 +2087,15 @@
#define WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP 0x0000000000000200ULL
/** Driver supports background radar/CAC detection */
#define WPA_DRIVER_RADAR_BACKGROUND 0x0000000000000400ULL
+/** Driver supports secure LTF in STA mode */
+#define WPA_DRIVER_FLAGS2_SEC_LTF_STA 0x0000000000000800ULL
+/** Driver supports secure RTT measurement exchange in STA mode */
+#define WPA_DRIVER_FLAGS2_SEC_RTT_STA 0x0000000000001000ULL
+/**
+ * Driver supports protection of range negotiation and measurement management
+ * frames in STA mode
+ */
+#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA 0x0000000000002000ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2175,6 +2208,9 @@
/* Maximum number of supported CSA counters */
u16 max_csa_counters;
+
+ /* Maximum number of supported AKM suites in commands */
+ unsigned int max_num_akms;
};
@@ -2362,6 +2398,11 @@
int center_frq2;
};
+struct wpa_mlo_signal_info {
+ u16 valid_links;
+ struct wpa_signal_info links[MAX_NUM_MLD_LINKS];
+};
+
/**
* struct wpa_channel_info - Information about the current channel
* @frequency: Center frequency of the primary 20 MHz channel
@@ -2594,6 +2635,90 @@
const u8 *pmkid;
};
+#define WPAS_MAX_PASN_PEERS 10
+
+enum pasn_status {
+ PASN_STATUS_SUCCESS = 0,
+ PASN_STATUS_FAILURE = 1,
+};
+
+/**
+ * struct pasn_peer - PASN peer parameters
+ *
+ * Used to process the PASN authentication event from the driver to
+ * userspace and to send a response back.
+ * @own_addr: Own MAC address specified by the driver to use for PASN
+ * handshake.
+ * @peer_addr: MAC address of the peer with which PASN authentication is to be
+ * performed.
+ * @network_id: Unique id for the network.
+ * This identifier is used as a unique identifier for each network
+ * block when using the control interface. Each network is allocated an
+ * id when it is being created, either when reading the configuration
+ * file or when a new network is added through the control interface.
+ * @akmp: Authentication key management protocol type supported.
+ * @cipher: Cipher suite.
+ * @group: Finite cyclic group. Default group used is 19 (ECC).
+ * @ltf_keyseed_required: Indicates whether LTF keyseed generation is required
+ * @status: PASN response status, %PASN_STATUS_SUCCESS for successful
+ * authentication, use %PASN_STATUS_FAILURE if PASN authentication
+ * fails or if wpa_supplicant fails to set the security ranging context to
+ * the driver
+ */
+struct pasn_peer {
+ u8 own_addr[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
+ int network_id;
+ int akmp;
+ int cipher;
+ int group;
+ bool ltf_keyseed_required;
+ enum pasn_status status;
+};
+
+/**
+ * struct pasn_auth - PASN authentication trigger parameters
+ *
+ * These are used across the PASN authentication event from the driver to
+ * userspace and to send a response to it.
+ * @action: Action type. Only significant for the event interface.
+ * @num_peers: The number of peers for which the PASN handshake is requested
+ * for.
+ * @peer: Holds the peer details.
+ */
+struct pasn_auth {
+ enum {
+ PASN_ACTION_AUTH,
+ PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT,
+ } action;
+ unsigned int num_peers;
+ struct pasn_peer peer[WPAS_MAX_PASN_PEERS];
+};
+
+/**
+ * struct secure_ranging_params - Parameters required to set secure ranging
+ * context for a peer.
+ *
+ * @action: Add or delete a security context to the driver.
+ * @own_addr: Own MAC address used during key derivation.
+ * @peer_addr: Address of the peer device.
+ * @cipher: Cipher suite.
+ * @tk_len: Length of temporal key.
+ * @tk: Temporal key buffer.
+ * @ltf_keyseed_len: Length of LTF keyseed.
+ * @ltf_keyeed: LTF keyseed buffer.
+ */
+struct secure_ranging_params {
+ u32 action;
+ const u8 *own_addr;
+ const u8 *peer_addr;
+ u32 cipher;
+ u8 tk_len;
+ const u8 *tk;
+ u8 ltf_keyseed_len;
+ const u8 *ltf_keyseed;
+};
+
/* enum nested_attr - Used to specify if subcommand uses nested attributes */
enum nested_attr {
NESTED_ATTR_NOT_USED = 0,
@@ -2601,6 +2726,34 @@
NESTED_ATTR_UNSPECIFIED = 2,
};
+/* Preferred channel list information */
+
+/* GO role */
+#define WEIGHTED_PCL_GO BIT(0)
+/* P2P Client role */
+#define WEIGHTED_PCL_CLI BIT(1)
+/* Must be considered for operating channel */
+#define WEIGHTED_PCL_MUST_CONSIDER BIT(2)
+/* Should be excluded in GO negotiation */
+#define WEIGHTED_PCL_EXCLUDE BIT(3)
+
+/* Preferred channel list with weight */
+struct weighted_pcl {
+ u32 freq; /* MHz */
+ u8 weight;
+ u32 flag; /* bitmap for WEIGHTED_PCL_* */
+};
+
+struct driver_sta_mlo_info {
+ u16 valid_links; /* bitmap of valid link IDs */
+ u8 ap_mld_addr[ETH_ALEN];
+ struct {
+ u8 addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ unsigned int freq;
+ } links[MAX_NUM_MLD_LINKS];
+};
+
/**
* struct wpa_driver_ops - Driver interface API definition
*
@@ -3848,6 +4001,14 @@
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
+ * mlo_signal_poll - Get current MLO connection information
+ * @priv: Private driver interface data
+ * @mlo_signal_info: MLO connection info structure
+ */
+ int (*mlo_signal_poll)(void *priv,
+ struct wpa_mlo_signal_info *mlo_signal_info);
+
+ /**
* channel_info - Get parameters of the current operating channel
* @priv: Private driver interface data
* @channel_info: Channel info structure
@@ -4445,14 +4606,17 @@
* @priv: Private driver interface data
* @if_type: Interface type
* @num: Number of channels
- * @freq_list: Preferred channel frequency list encoded in MHz values
+ * @freq_list: Weighted preferred channel list
* Returns 0 on success, -1 on failure
*
* This command can be used to query the preferred frequency list from
- * the driver specific to a particular interface type.
+ * the driver specific to a particular interface type. The freq_list
+ * array needs to have room for *num entries. *num will be updated to
+ * indicate the number of entries fetched from the driver.
*/
int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type,
- unsigned int *num, unsigned int *freq_list);
+ unsigned int *num,
+ struct weighted_pcl *freq_list);
/**
* set_prob_oper_freq - Indicate probable P2P operating channel
@@ -4641,6 +4805,37 @@
*/
int (*dpp_listen)(void *priv, bool enable);
+ /**
+ * set_secure_ranging_ctx - Add or delete secure ranging parameters of
+ * the specified peer to the driver.
+ * @priv: Private driver interface data
+ * @params: Secure ranging parameters
+ * Returns: 0 on success, -1 on failure
+ *
+ */
+ int (*set_secure_ranging_ctx)(void *priv,
+ struct secure_ranging_params *params);
+
+ /**
+ * send_pasn_resp - Send PASN response for a set of peers to the
+ * driver.
+ * @priv: Private driver interface data
+ * @params: Parameters holding peers and respective status.
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*send_pasn_resp)(void *priv, struct pasn_auth *params);
+
+ /**
+ * get_sta_mlo_info - Get the current multi-link association info
+ * @priv: Private driver interface data
+ * @mlo: Pointer to fill multi-link association info
+ * Returns: 0 on success, -1 on failure
+ *
+ * This callback is used to fetch multi-link of the current association.
+ */
+ int (*get_sta_mlo_info)(void *priv,
+ struct driver_sta_mlo_info *mlo_info);
+
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
const u8 *match, size_t match_len,
@@ -5234,6 +5429,30 @@
* EVENT_CCA_NOTIFY - Notification that CCA has completed
*/
EVENT_CCA_NOTIFY,
+
+ /**
+ * EVENT_PASN_AUTH - This event is used by the driver that requests
+ * PASN authentication and secure ranging context for multiple peers.
+ */
+ EVENT_PASN_AUTH,
+
+ /**
+ * EVENT_LINK_CH_SWITCH - MLD AP link decided to switch channels
+ *
+ * Described in wpa_event_data.ch_switch.
+ *
+ */
+ EVENT_LINK_CH_SWITCH,
+
+ /**
+ * EVENT_LINK_CH_SWITCH_STARTED - MLD AP link started to switch channels
+ *
+ * This is a pre-switch event indicating the shortly following switch
+ * of operating channels.
+ *
+ * Described in wpa_event_data.ch_switch.
+ */
+ EVENT_LINK_CH_SWITCH_STARTED,
};
@@ -5856,6 +6075,7 @@
const u8 *src;
const u8 *data;
size_t data_len;
+ enum frame_encryption encrypted;
} eapol_rx;
/**
@@ -5948,6 +6168,7 @@
* @ch_width: Channel width
* @cf1: Center frequency 1
* @cf2: Center frequency 2
+ * @link_id: Link ID of the MLO link
*/
struct ch_switch {
int freq;
@@ -5956,6 +6177,7 @@
enum chan_width ch_width;
int cf1;
int cf2;
+ int link_id;
} ch_switch;
/**
@@ -6133,6 +6355,12 @@
struct bss_color_collision {
u64 bitmap;
} bss_color_collision;
+
+ /**
+ * struct pasn_auth - Data for EVENT_PASN_AUTH
+ */
+ struct pasn_auth pasn_auth;
+
};
/**
@@ -6194,6 +6422,20 @@
event.eapol_rx.src = src;
event.eapol_rx.data = data;
event.eapol_rx.data_len = data_len;
+ event.eapol_rx.encrypted = FRAME_ENCRYPTION_UNKNOWN;
+ wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
+}
+
+static inline void drv_event_eapol_rx2(void *ctx, const u8 *src, const u8 *data,
+ size_t data_len,
+ enum frame_encryption encrypted)
+{
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.eapol_rx.src = src;
+ event.eapol_rx.data = data;
+ event.eapol_rx.data_len = data_len;
+ event.eapol_rx.encrypted = encrypted;
wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
}
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 8db7861..0ac0aa6 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -95,6 +95,9 @@
E2S(CCA_STARTED_NOTIFY);
E2S(CCA_ABORTED_NOTIFY);
E2S(CCA_NOTIFY);
+ E2S(PASN_AUTH);
+ E2S(LINK_CH_SWITCH);
+ E2S(LINK_CH_SWITCH_STARTED);
}
return "UNKNOWN";
@@ -117,6 +120,8 @@
return "80+80 MHz";
case CHAN_WIDTH_160:
return "160 MHz";
+ case CHAN_WIDTH_320:
+ return "320 MHz";
default:
return "unknown";
}
@@ -136,6 +141,8 @@
case CHAN_WIDTH_80P80:
case CHAN_WIDTH_160:
return 160;
+ case CHAN_WIDTH_320:
+ return 320;
default:
return 0;
}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5892fc1..1385edb 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -31,6 +31,8 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_common.h"
+#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "netlink.h"
#include "linux_defines.h"
#include "linux_ioctl.h"
@@ -219,6 +221,8 @@
return CHAN_WIDTH_80P80;
case NL80211_CHAN_WIDTH_160:
return CHAN_WIDTH_160;
+ case NL80211_CHAN_WIDTH_320:
+ return CHAN_WIDTH_320;
}
return CHAN_WIDTH_UNKNOWN;
}
@@ -270,8 +274,13 @@
if (drv->associated)
os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
drv->associated = 0;
+ drv->sta_mlo_info.valid_links = 0;
os_memset(drv->bssid, 0, ETH_ALEN);
drv->first_bss->freq = 0;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = NULL;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
}
@@ -1015,6 +1024,20 @@
}
+static int nl80211_get_sta_mlo_info(void *priv,
+ struct driver_sta_mlo_info *mlo_info)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (!drv->associated)
+ return -1;
+
+ os_memcpy(mlo_info, &drv->sta_mlo_info, sizeof(*mlo_info));
+ return 0;
+}
+
+
static void wpa_driver_nl80211_event_newlink(
struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
int ifindex, const char *ifname)
@@ -1440,6 +1463,8 @@
u8 assoc_bssid[ETH_ALEN];
u8 assoc_ssid[SSID_MAX_LEN];
u8 assoc_ssid_len;
+ u8 bssid[MAX_NUM_MLD_LINKS][ETH_ALEN];
+ unsigned int freq[MAX_NUM_MLD_LINKS];
};
static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
@@ -1452,9 +1477,11 @@
[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ [NL80211_BSS_MLO_LINK_ID] = { .type = NLA_U8 },
};
struct nl80211_get_assoc_freq_arg *ctx = arg;
enum nl80211_bss_status status;
+ struct wpa_driver_nl80211_data *drv = ctx->drv;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -1467,9 +1494,25 @@
status = nla_get_u32(bss[NL80211_BSS_STATUS]);
if (status == NL80211_BSS_STATUS_ASSOCIATED &&
bss[NL80211_BSS_FREQUENCY]) {
- ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
- ctx->assoc_freq);
+ int link_id = -1;
+ u32 freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+
+ if (bss[NL80211_BSS_MLO_LINK_ID])
+ link_id = nla_get_u8(bss[NL80211_BSS_MLO_LINK_ID]);
+
+ if (link_id >= 0 && link_id < MAX_NUM_MLD_LINKS) {
+ ctx->freq[link_id] = freq;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLO link %d associated on %u MHz",
+ link_id, ctx->freq[link_id]);
+ }
+
+ if (!drv->sta_mlo_info.valid_links ||
+ drv->mlo_assoc_link_id == link_id) {
+ ctx->assoc_freq = freq;
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ ctx->assoc_freq);
+ }
}
if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
bss[NL80211_BSS_FREQUENCY]) {
@@ -1479,10 +1522,26 @@
}
if (status == NL80211_BSS_STATUS_ASSOCIATED &&
bss[NL80211_BSS_BSSID]) {
- os_memcpy(ctx->assoc_bssid,
- nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: Associated with "
- MACSTR, MAC2STR(ctx->assoc_bssid));
+ int link_id = -1;
+ const u8 *bssid = nla_data(bss[NL80211_BSS_BSSID]);
+
+ if (bss[NL80211_BSS_MLO_LINK_ID])
+ link_id = nla_get_u8(bss[NL80211_BSS_MLO_LINK_ID]);
+
+ if (link_id >= 0 && link_id < MAX_NUM_MLD_LINKS) {
+ os_memcpy(ctx->bssid[link_id], bssid, ETH_ALEN);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLO link %d associated with "
+ MACSTR, link_id, MAC2STR(bssid));
+ }
+
+ if (!drv->sta_mlo_info.valid_links ||
+ drv->mlo_assoc_link_id == link_id) {
+ os_memcpy(ctx->assoc_bssid, bssid, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(bssid));
+ }
+
}
if (status == NL80211_BSS_STATUS_ASSOCIATED &&
@@ -1568,6 +1627,14 @@
"associated BSS from scan results: %u MHz", freq);
if (freq)
drv->assoc_freq = freq;
+
+ if (drv->sta_mlo_info.valid_links) {
+ int i;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
+ drv->sta_mlo_info.links[i].freq = arg.freq[i];
+ }
+
return drv->assoc_freq;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -1639,7 +1706,7 @@
int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
- struct wpa_signal_info *sig)
+ const u8 *bssid, struct wpa_signal_info *sig)
{
struct nl_msg *msg;
@@ -1647,7 +1714,7 @@
sig->current_txrate = 0;
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) {
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -2385,8 +2452,7 @@
#ifdef CONFIG_PASN
/* register for PASN Authentication frames */
- if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- nl80211_register_frame(bss, bss->nl_mgmt, type,
+ if (nl80211_register_frame(bss, bss->nl_mgmt, type,
(u8 *) "\x07\x00", 2, false))
ret = -1;
#endif /* CONFIG_PASN */
@@ -3176,7 +3242,9 @@
__AKM(IEEE8021X_SHA256, 802_1X_SHA256);
__AKM(PSK_SHA256, PSK_SHA256);
__AKM(SAE, SAE);
+ __AKM(SAE_EXT_KEY, SAE_EXT_KEY);
__AKM(FT_SAE, FT_SAE);
+ __AKM(FT_SAE_EXT_KEY, FT_SAE_EXT_KEY);
__AKM(CCKM, CCKM);
__AKM(OSEN, OSEN);
__AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
@@ -4775,7 +4843,8 @@
if (drv->device_ap_sme) {
u32 flags = 0;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) {
+ if (params->key_mgmt_suites & (WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_SAE_EXT_KEY)) {
/* Add the previously used flag attribute to support
* older kernel versions and the newer flag bit for
* newer kernels. */
@@ -4946,8 +5015,7 @@
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_SAE
- if (((params->key_mgmt_suites & WPA_KEY_MGMT_SAE) ||
- (params->key_mgmt_suites & WPA_KEY_MGMT_FT_SAE)) &&
+ if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
goto fail;
#endif /* CONFIG_SAE */
@@ -5055,6 +5123,9 @@
case 160:
cw = NL80211_CHAN_WIDTH_160;
break;
+ case 320:
+ cw = NL80211_CHAN_WIDTH_320;
+ break;
default:
return -EINVAL;
}
@@ -5107,8 +5178,9 @@
NL80211_CHAN_NO_HT))
return -ENOBUFS;
}
- if (freq->radar_background)
- nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND);
+ if (freq->radar_background &&
+ nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND))
+ return -ENOBUFS;
return 0;
}
@@ -6239,6 +6311,17 @@
}
+static unsigned int num_bits_set(u32 val)
+{
+ unsigned int c;
+
+ for (c = 0; val; c++)
+ val &= val - 1;
+
+ return c;
+}
+
+
static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
struct nl_msg *msg)
@@ -6358,7 +6441,9 @@
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_SAE_EXT_KEY ||
params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE_EXT_KEY ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ||
params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
@@ -6368,71 +6453,111 @@
params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 ||
params->key_mgmt_suite == WPA_KEY_MGMT_OWE ||
params->key_mgmt_suite == WPA_KEY_MGMT_DPP) {
- int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ u32 *mgmt;
+ unsigned int akm_count = 1, i;
+
+ /*
+ * Make sure the driver has capability to handle default AKM in
+ * key_mgmt_suite plus allowed AKMs in allowed_key_mgmts.
+ */
+ if (drv->capa.max_num_akms <=
+ num_bits_set(params->allowed_key_mgmts)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Not enough support for the allowed AKMs (max_num_akms=%u <= num_bits_set=%u)",
+ drv->capa.max_num_akms,
+ num_bits_set(params->allowed_key_mgmts));
+ return -1;
+ }
+
+ mgmt = os_malloc(sizeof(u32) * drv->capa.max_num_akms);
+ if (!mgmt)
+ return -1;
+
+ mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
switch (params->key_mgmt_suite) {
case WPA_KEY_MGMT_CCKM:
- mgmt = RSN_AUTH_KEY_MGMT_CCKM;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_CCKM;
break;
case WPA_KEY_MGMT_IEEE8021X:
- mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
break;
case WPA_KEY_MGMT_FT_IEEE8021X:
- mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X;
break;
case WPA_KEY_MGMT_FT_PSK:
- mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_PSK;
break;
case WPA_KEY_MGMT_IEEE8021X_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
break;
case WPA_KEY_MGMT_PSK_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256;
break;
case WPA_KEY_MGMT_OSEN:
- mgmt = RSN_AUTH_KEY_MGMT_OSEN;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN;
break;
case WPA_KEY_MGMT_SAE:
- mgmt = RSN_AUTH_KEY_MGMT_SAE;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_SAE;
+ break;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ mgmt[0] = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
break;
case WPA_KEY_MGMT_FT_SAE:
- mgmt = RSN_AUTH_KEY_MGMT_FT_SAE;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE;
+ break;
+ case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
- mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
- mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
break;
case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
- mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
break;
case WPA_KEY_MGMT_FILS_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA256;
break;
case WPA_KEY_MGMT_FILS_SHA384:
- mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA384;
break;
case WPA_KEY_MGMT_FT_FILS_SHA256:
- mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
break;
case WPA_KEY_MGMT_FT_FILS_SHA384:
- mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
break;
case WPA_KEY_MGMT_OWE:
- mgmt = RSN_AUTH_KEY_MGMT_OWE;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_OWE;
break;
case WPA_KEY_MGMT_DPP:
- mgmt = RSN_AUTH_KEY_MGMT_DPP;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_DPP;
break;
case WPA_KEY_MGMT_PSK:
default:
- mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+ mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
break;
}
- wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
- if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
+
+ if (drv->capa.max_num_akms > 1) {
+ akm_count += wpa_key_mgmt_to_suites(
+ params->allowed_key_mgmts, &mgmt[1],
+ drv->capa.max_num_akms - 1);
+ }
+
+ for (i = 0; i < akm_count; i++)
+ wpa_printf(MSG_DEBUG, " * akm[%d]=0x%x", i, mgmt[i]);
+
+ if (nla_put(msg, NL80211_ATTR_AKM_SUITES,
+ akm_count * sizeof(u32), mgmt)) {
+ os_free(mgmt);
return -1;
+ }
+
+ os_free(mgmt);
}
#ifdef CONFIG_DRIVER_NL80211_BRCM
@@ -6513,13 +6638,13 @@
nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1;
- if ((
#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
+ if (((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
+ (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)) &&
#else
- params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
#endif /* CONFIG_DRIVER_NL80211_BRCM */
- params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
return -1;
@@ -6540,9 +6665,8 @@
#ifdef CONFIG_DRIVER_NL80211_QCA
if (params->req_key_mgmt_offload && params->psk &&
- (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
- params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_wpa_psk_no_sae(params->allowed_key_mgmts))) {
wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
ret = issue_key_mgmt_set_key(drv, params->psk, 32);
if (ret)
@@ -6569,13 +6693,13 @@
goto fail;
#ifdef CONFIG_SAE
- if ((
#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
+ if (((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
+ (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)) &&
#else
- params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ if ((wpa_key_mgmt_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_sae(params->allowed_key_mgmts)) &&
#endif /* CONFIG_DRIVER_NL80211_BRCM */
- params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
nl80211_put_sae_pwe(msg, params->sae_pwe) < 0)
goto fail;
#endif /* CONFIG_SAE */
@@ -6683,13 +6807,13 @@
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- if (
#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
+ if ((params->key_mgmt_suite & WPA_KEY_MGMT_SAE) ||
+ (params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE))
#else
- params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ if (wpa_key_mgmt_sae(params->key_mgmt_suite) ||
+ wpa_key_mgmt_sae(params->allowed_key_mgmts))
#endif /* CONFIG_DRIVER_NL80211_BRCM */
- params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
bss->use_nl_connect = 1;
else
bss->use_nl_connect = 0;
@@ -7003,14 +7127,17 @@
struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
int ret;
+ const u8 *connected_addr = drv->sta_mlo_info.valid_links ?
+ drv->sta_mlo_info.ap_mld_addr : drv->bssid;
- if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
+ if (!drv->associated && is_zero_ether_addr(connected_addr) &&
+ !authorized) {
wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
- MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
+ MACSTR, authorized ? "" : "un", MAC2STR(connected_addr));
os_memset(&upd, 0, sizeof(upd));
upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
@@ -7018,7 +7145,7 @@
upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr) ||
nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
nlmsg_free(msg);
return -ENOBUFS;
@@ -8782,7 +8909,7 @@
int res;
os_memset(si, 0, sizeof(*si));
- res = nl80211_get_link_signal(drv, si);
+ res = nl80211_get_link_signal(drv, drv->bssid, si);
if (res) {
if (drv->nlmode != NL80211_IFTYPE_ADHOC &&
drv->nlmode != NL80211_IFTYPE_MESH_POINT)
@@ -8798,6 +8925,163 @@
}
+static int get_links_noise(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_mlo_signal_info *mlo_sig = arg;
+ int i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to parse nested attributes");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo_sig->valid_links & BIT(i)))
+ continue;
+
+ if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ mlo_sig->links[i].frequency)
+ continue;
+
+ mlo_sig->links[i].current_noise =
+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ break;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_links_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_mlo_signal_info *mlo_sig)
+{
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ return send_and_recv_msgs(drv, msg, get_links_noise, mlo_sig,
+ NULL, NULL);
+}
+
+
+static int get_links_channel_width(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_mlo_signal_info *mlo_sig = arg;
+ struct nlattr *link;
+ int rem_links;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_MLO_LINKS])
+ return NL_SKIP;
+
+ nla_for_each_nested(link, tb[NL80211_ATTR_MLO_LINKS], rem_links) {
+ struct nlattr *tb2[NL80211_ATTR_MAX + 1];
+ int link_id;
+
+ nla_parse(tb2, NL80211_ATTR_MAX, nla_data(link), nla_len(link),
+ NULL);
+
+ if (!tb2[NL80211_ATTR_MLO_LINK_ID])
+ continue;
+
+ link_id = nla_get_u8(tb2[NL80211_ATTR_MLO_LINK_ID]);
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ continue;
+
+ if (!tb2[NL80211_ATTR_CHANNEL_WIDTH])
+ continue;
+ mlo_sig->links[link_id].chanwidth = convert2width(
+ nla_get_u32(tb2[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb2[NL80211_ATTR_CENTER_FREQ1])
+ mlo_sig->links[link_id].center_frq1 =
+ nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb2[NL80211_ATTR_CENTER_FREQ2])
+ mlo_sig->links[link_id].center_frq2 =
+ nla_get_u32(tb2[NL80211_ATTR_CENTER_FREQ2]);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_links_channel_width(struct wpa_driver_nl80211_data *drv,
+ struct wpa_mlo_signal_info *mlo_sig)
+{
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ return send_and_recv_msgs(drv, msg, get_links_channel_width, mlo_sig,
+ NULL, NULL);
+}
+
+
+static int nl80211_mlo_signal_poll(void *priv,
+ struct wpa_mlo_signal_info *mlo_si)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int res;
+ int i;
+
+ if (drv->nlmode != NL80211_IFTYPE_STATION ||
+ !drv->sta_mlo_info.valid_links)
+ return -1;
+
+ os_memset(mlo_si, 0, sizeof(*mlo_si));
+ mlo_si->valid_links = drv->sta_mlo_info.valid_links;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo_si->valid_links & BIT(i)))
+ continue;
+
+ res = nl80211_get_link_signal(drv,
+ drv->sta_mlo_info.links[i].bssid,
+ &mlo_si->links[i]);
+ if (res != 0)
+ return res;
+
+ mlo_si->links[i].center_frq1 = -1;
+ mlo_si->links[i].center_frq2 = -1;
+ mlo_si->links[i].chanwidth = CHAN_WIDTH_UNKNOWN;
+ mlo_si->links[i].current_noise = WPA_INVALID_NOISE;
+ mlo_si->links[i].frequency = drv->sta_mlo_info.links[i].freq;
+ }
+
+ res = nl80211_get_links_channel_width(drv, mlo_si);
+ if (res != 0)
+ return res;
+
+ return nl80211_get_links_noise(drv, mlo_si);
+}
+
+
static int nl80211_set_param(void *priv, const char *param)
{
struct i802_bss *bss = priv;
@@ -9886,6 +10170,34 @@
return pos - buf;
pos += res;
+ if (drv->sta_mlo_info.valid_links) {
+ int i;
+ struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info;
+
+ res = os_snprintf(pos, end - pos,
+ "ap_mld_addr=" MACSTR "\n",
+ MAC2STR(mlo->ap_mld_addr));
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo->valid_links & BIT(i)))
+ continue;
+
+ res = os_snprintf(pos, end - pos,
+ "link_addr[%u]=" MACSTR "\n"
+ "link_bssid[%u]=" MACSTR "\n"
+ "link_freq[%u]=%u\n",
+ i, MAC2STR(mlo->links[i].addr),
+ i, MAC2STR(mlo->links[i].bssid),
+ i, mlo->links[i].freq);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+ }
+
if (drv->has_capability) {
res = os_snprintf(pos, end - pos,
"capa.key_mgmt=0x%x\n"
@@ -11441,9 +11753,33 @@
struct nl80211_pcl {
unsigned int num;
- unsigned int *freq_list;
+ struct weighted_pcl *freq_list;
};
+static void get_pcl_attr_values(struct weighted_pcl *wpcl, struct nlattr *nl[])
+{
+ if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ])
+ wpcl->freq = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]);
+ if (nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT])
+ wpcl->weight = nla_get_u8(nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]);
+ if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]) {
+ u32 flags = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]);
+
+ wpcl->flag = 0;
+ if (flags & BIT(0))
+ wpcl->flag |= WEIGHTED_PCL_GO;
+ if (flags & BIT(1))
+ wpcl->flag |= WEIGHTED_PCL_CLI;
+ if (flags & BIT(2))
+ wpcl->flag |= WEIGHTED_PCL_MUST_CONSIDER;
+ if (flags & BIT(3))
+ wpcl->flag |= WEIGHTED_PCL_EXCLUDE;
+ } else {
+ wpcl->flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
+ }
+}
+
+
static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -11452,6 +11788,7 @@
struct nlattr *nl_vend, *attr;
enum qca_iface_type iface_type;
struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ struct nlattr *nl_pcl[QCA_WLAN_VENDOR_ATTR_PCL_MAX + 1];
unsigned int num, max_num;
u32 *freqs;
@@ -11477,26 +11814,69 @@
wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
iface_type);
- attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
- if (!attr) {
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL];
+ if (attr) {
+ int rem;
+ struct nlattr *wpcl = attr;
+ unsigned int i;
+
+ num = 0;
+ nla_for_each_nested(attr, wpcl, rem) {
+ if (num == param->num)
+ break; /* not enough room for all entries */
+ if (nla_parse(nl_pcl, QCA_WLAN_VENDOR_ATTR_PCL_MAX,
+ nla_data(attr), nla_len(attr), NULL)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to parse PCL info");
+ param->num = 0;
+ return NL_SKIP;
+ }
+ get_pcl_attr_values(¶m->freq_list[num], nl_pcl);
+ num++;
+ }
+ param->num = num;
+
+ /* Sort frequencies based on their weight */
+ for (i = 0; i < num; i++) {
+ unsigned int j;
+
+ for (j = i + 1; j < num; j++) {
+ if (param->freq_list[i].weight <
+ param->freq_list[j].weight) {
+ struct weighted_pcl tmp;
+
+ tmp = param->freq_list[i];
+ param->freq_list[i] =
+ param->freq_list[j];
+ param->freq_list[j] = tmp;
+ }
+ }
+ }
+ } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver does not provide weighted PCL; use the non-weighted variant");
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
+ /*
+ * param->num has the maximum number of entries for which there
+ * is room in the freq_list provided by the caller.
+ */
+ freqs = nla_data(attr);
+ max_num = nla_len(attr) / sizeof(u32);
+ if (max_num > param->num)
+ max_num = param->num;
+ for (num = 0; num < max_num; num++) {
+ param->freq_list[num].freq = freqs[num];
+ param->freq_list[num].flag =
+ WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
+ }
+ param->num = num;
+ } else {
wpa_printf(MSG_ERROR,
"nl80211: preferred_freq_list couldn't be found");
param->num = 0;
return NL_SKIP;
}
-
- /*
- * param->num has the maximum number of entries for which there
- * is room in the freq_list provided by the caller.
- */
- freqs = nla_data(attr);
- max_num = nla_len(attr) / sizeof(u32);
- if (max_num > param->num)
- max_num = param->num;
- for (num = 0; num < max_num; num++)
- param->freq_list[num] = freqs[num];
- param->num = num;
-
return NL_SKIP;
}
@@ -11504,7 +11884,7 @@
static int nl80211_get_pref_freq_list(void *priv,
enum wpa_driver_if_type if_type,
unsigned int *num,
- unsigned int *freq_list)
+ struct weighted_pcl *freq_list)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -11561,7 +11941,8 @@
}
nla_nest_end(msg, params);
- os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
+ if (freq_list)
+ os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl));
ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, ¶m,
NULL, NULL);
if (ret) {
@@ -11573,8 +11954,10 @@
*num = param.num;
for (i = 0; i < *num; i++) {
- wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
- i, freq_list[i]);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: preferred_channel_list[%d]=%d[%d]:0x%x",
+ i, freq_list[i].freq, freq_list[i].weight,
+ freq_list[i].flag);
}
return 0;
@@ -12007,6 +12390,169 @@
#endif /* CONFIG_MBO */
+
+#ifdef CONFIG_PASN
+
+static int nl80211_send_pasn_resp(void *priv, struct pasn_auth *params)
+{
+ unsigned int i;
+ struct i802_bss *bss = priv;
+ struct nl_msg *msg = NULL;
+ struct nlattr *nlpeers, *attr, *attr1;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: PASN authentication response for %d entries",
+ params->num_peers);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_PASN))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ nlpeers = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEERS);
+ if (!nlpeers)
+ goto fail;
+
+ for (i = 0; i < params->num_peers; i++) {
+ attr1 = nla_nest_start(msg, i);
+ if (!attr1 ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR,
+ ETH_ALEN, params->peer[i].own_addr) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR,
+ ETH_ALEN, params->peer[i].peer_addr))
+ goto fail;
+
+ if (params->peer[i].status == 0)
+ nla_put_flag(msg,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Own address[%u]: " MACSTR
+ " Peer address[%u]: " MACSTR " Status: %s",
+ i, MAC2STR(params->peer[i].own_addr), i,
+ MAC2STR(params->peer[i].peer_addr),
+ params->peer[i].status ? "Fail" : "Success");
+ nla_nest_end(msg, attr1);
+ }
+
+ nla_nest_end(msg, nlpeers);
+ nla_nest_end(msg, attr);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static u32 wpa_ltf_keyseed_len_to_sha_type(size_t len)
+{
+ if (len == SHA384_MAC_LEN)
+ return QCA_WLAN_VENDOR_SHA_384;
+ if (len == SHA256_MAC_LEN)
+ return QCA_WLAN_VENDOR_SHA_256;
+
+ wpa_printf(MSG_ERROR, "nl80211: Unexpected LTF keyseed len %zu", len);
+ return (u32) -1;
+}
+
+
+static int nl80211_set_secure_ranging_ctx(void *priv,
+ struct secure_ranging_params *params)
+{
+ int ret;
+ u32 suite;
+ struct nlattr *attr;
+ struct nl_msg *msg = NULL;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ /* Configure secure ranging context only to the drivers that support it.
+ */
+ if (!drv->secure_ranging_ctx_vendor_cmd_avail)
+ return 0;
+
+ if (!params->peer_addr || !params->own_addr)
+ return -1;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: Secure ranging context for " MACSTR,
+ MAC2STR(params->peer_addr));
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR,
+ ETH_ALEN, params->peer_addr) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR,
+ ETH_ALEN, params->own_addr) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION,
+ params->action))
+ goto fail;
+
+ if (params->cipher) {
+ suite = wpa_cipher_to_cipher_suite(params->cipher);
+ if (!suite ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER,
+ suite))
+ goto fail;
+ }
+
+ if (params->tk_len && params->tk) {
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK,
+ params->tk_len, params->tk))
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "nl80211: TK",
+ params->tk, params->tk_len);
+ }
+
+ if (params->ltf_keyseed_len && params->ltf_keyseed) {
+ u32 sha_type = wpa_ltf_keyseed_len_to_sha_type(
+ params->ltf_keyseed_len);
+
+ if (sha_type == (u32) -1 ||
+ nla_put_u32(
+ msg,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE,
+ sha_type) ||
+ nla_put(msg,
+ QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED,
+ params->ltf_keyseed_len, params->ltf_keyseed))
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "nl80211: LTF keyseed",
+ params->ltf_keyseed, params->ltf_keyseed_len);
+ }
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set secure ranging context failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
@@ -12496,6 +13042,7 @@
.resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
+ .mlo_signal_poll = nl80211_mlo_signal_poll,
.channel_info = nl80211_channel_info,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
@@ -12566,6 +13113,10 @@
#endif /* CONFIG_MBO */
.set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
.add_sta_node = nl80211_add_sta_node,
+#ifdef CONFIG_PASN
+ .send_pasn_resp = nl80211_send_pasn_resp,
+ .set_secure_ranging_ctx = nl80211_set_secure_ranging_ctx,
+#endif /* CONFIG_PASN */
#endif /* CONFIG_DRIVER_NL80211_QCA */
.do_acs = nl80211_do_acs,
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
@@ -12576,6 +13127,7 @@
#ifdef CONFIG_DPP
.dpp_listen = nl80211_dpp_listen,
#endif /* CONFIG_DPP */
+ .get_sta_mlo_info = nl80211_get_sta_mlo_info,
#ifdef CONFIG_TESTING_OPTIONS
.register_frame = testing_nl80211_register_frame,
.radio_disable = testing_nl80211_radio_disable,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 8ad7184..be5783b 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -128,6 +128,8 @@
u8 bssid[ETH_ALEN];
u8 prev_bssid[ETH_ALEN];
int associated;
+ int mlo_assoc_link_id;
+ struct driver_sta_mlo_info sta_mlo_info;
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
enum nl80211_iftype nlmode;
@@ -180,6 +182,8 @@
unsigned int unsol_bcast_probe_resp:1;
unsigned int qca_do_acs:1;
unsigned int brcm_do_acs:1;
+ unsigned int uses_6ghz:1;
+ unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -235,7 +239,6 @@
bool roam_indication_done;
u8 *pending_roam_data;
size_t pending_roam_data_len;
- struct os_reltime pending_roam_ind_time;
#endif /* CONFIG_DRIVER_NL80211_QCA */
};
@@ -269,7 +272,7 @@
int is_sta_interface(enum nl80211_iftype nlmode);
int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv);
int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
- struct wpa_signal_info *sig);
+ const u8 *bssid, struct wpa_signal_info *sig);
int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
struct wpa_signal_info *sig_change);
int nl80211_get_wiphy_index(struct i802_bss *bss);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 75df36c..46592b3 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -294,6 +294,9 @@
case RSN_AUTH_KEY_MGMT_FT_SAE:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE;
break;
+ case RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY;
+ break;
case RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384;
break;
@@ -330,6 +333,9 @@
case RSN_AUTH_KEY_MGMT_SAE:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE;
break;
+ case RSN_AUTH_KEY_MGMT_SAE_EXT_KEY:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY;
+ break;
}
}
@@ -668,6 +674,25 @@
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_RADAR_BACKGROUND))
capa->flags2 |= WPA_DRIVER_RADAR_BACKGROUND;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SECURE_LTF)) {
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA;
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_AP;
+ }
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SECURE_RTT)) {
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_STA;
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_AP;
+ }
+
+ if (ext_feature_isset(
+ ext_features, len,
+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE)) {
+ capa->flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA;
+ capa->flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP;
+ }
}
@@ -1029,6 +1054,9 @@
case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO:
drv->get_sta_info_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT:
+ drv->secure_ranging_ctx_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
@@ -1086,6 +1114,10 @@
if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG])
capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY;
+ if (tb[NL80211_ATTR_MAX_NUM_AKM_SUITES])
+ capa->max_num_akms =
+ nla_get_u16(tb[NL80211_ATTR_MAX_NUM_AKM_SUITES]);
+
return NL_SKIP;
}
@@ -1164,6 +1196,9 @@
if (info->update_ft_ies_supported)
drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES;
+ if (!drv->capa.max_num_akms)
+ drv->capa.max_num_akms = 1;
+
return 0;
}
@@ -1326,6 +1361,22 @@
drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_AP;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON, &info))
drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_STA_CFON;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA, &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP, &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_AP;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA, &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_STA;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP, &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_AP;
+ if (check_feature(
+ QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA,
+ &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA;
+ if (check_feature(
+ QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP,
+ &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP;
os_free(info.flags);
}
@@ -2474,7 +2525,8 @@
}
-static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes,
+static void nl80211_dump_chan_list(struct wpa_driver_nl80211_data *drv,
+ struct hostapd_hw_modes *modes,
u16 num_modes)
{
int i;
@@ -2492,6 +2544,9 @@
for (j = 0; j < mode->num_channels; j++) {
struct hostapd_channel_data *chan = &mode->channels[j];
+ if (chan->freq >= 5925 && chan->freq <= 7125 &&
+ !(chan->flag & HOSTAPD_CHAN_DISABLED))
+ drv->uses_6ghz = true;
res = os_snprintf(pos, end - pos, " %d%s%s%s",
chan->freq,
(chan->flag & HOSTAPD_CHAN_DISABLED) ?
@@ -2563,7 +2618,7 @@
modes = wpa_driver_nl80211_postprocess_modes(result.modes,
num_modes);
- nl80211_dump_chan_list(modes, *num_modes);
+ nl80211_dump_chan_list(drv, modes, *num_modes);
return modes;
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 5c103a4..50fe438 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -178,6 +178,11 @@
C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED)
C2S(NL80211_CMD_SET_FILS_AAD)
C2S(NL80211_CMD_ASSOC_COMEBACK)
+ C2S(NL80211_CMD_ADD_LINK)
+ C2S(NL80211_CMD_REMOVE_LINK)
+ C2S(NL80211_CMD_ADD_LINK_STA)
+ C2S(NL80211_CMD_MODIFY_LINK_STA)
+ C2S(NL80211_CMD_REMOVE_LINK_STA)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@@ -414,11 +419,147 @@
}
}
+
+static void
+nl80211_parse_qca_vendor_mlo_link_info(struct driver_sta_mlo_info *mlo,
+ struct nlattr *mlo_links)
+{
+ struct nlattr *link;
+ int rem_links;
+
+ nla_for_each_nested(link, mlo_links, rem_links) {
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX + 1];
+ int link_id;
+
+ nla_parse(tb,QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX, nla_data(link),
+ nla_len(link), NULL);
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID])
+ continue;
+
+ link_id = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID]);
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ continue;
+
+ mlo->valid_links |= BIT(link_id);
+ os_memcpy(mlo->links[link_id].addr,
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR]),
+ ETH_ALEN);
+ os_memcpy(mlo->links[link_id].bssid,
+ nla_data(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID]),
+ ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: MLO link[%u] addr " MACSTR
+ " bssid " MACSTR,
+ link_id, MAC2STR(mlo->links[link_id].addr),
+ MAC2STR(mlo->links[link_id].bssid));
+ }
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
+static void nl80211_parse_mlo_link_info(struct driver_sta_mlo_info *mlo,
+ struct nlattr *mlo_links)
+{
+ struct nlattr *link;
+ int rem_links;
+
+ nla_for_each_nested(link, mlo_links, rem_links) {
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ int link_id;
+
+ nla_parse(tb, NL80211_ATTR_MAX, nla_data(link), nla_len(link),
+ NULL);
+
+ if (!tb[NL80211_ATTR_MLO_LINK_ID] || !tb[NL80211_ATTR_MAC] ||
+ !tb[NL80211_ATTR_BSSID])
+ continue;
+
+ link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ continue;
+
+ mlo->valid_links |= BIT(link_id);
+ os_memcpy(mlo->links[link_id].addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ os_memcpy(mlo->links[link_id].bssid,
+ nla_data(tb[NL80211_ATTR_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: MLO link[%u] addr " MACSTR
+ " bssid " MACSTR,
+ link_id, MAC2STR(mlo->links[link_id].addr),
+ MAC2STR(mlo->links[link_id].bssid));
+ }
+}
+
+
+static int nl80211_get_assoc_link_id(const u8 *data, u8 len)
+{
+ if (!(data[0] & BASIC_MULTI_LINK_CTRL0_PRES_LINK_ID))
+ return -1;
+
+#define BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX \
+ (2 + /* Multi-Link Control field */ \
+ 1 + /* Common Info Length field (Basic) */ \
+ ETH_ALEN) /* MLD MAC Address field (Basic) */
+ if (len <= BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX)
+ return -1;
+
+ return data[BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX] & 0x0F;
+}
+
+
+static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv,
+ bool qca_roam_auth,
+ struct nlattr *addr,
+ struct nlattr *mlo_links,
+ struct nlattr *resp_ie)
+{
+ const u8 *ml_ie;
+ struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info;
+
+ if (!addr || !mlo_links || !resp_ie)
+ return;
+
+ ml_ie = get_ml_ie(nla_data(resp_ie), nla_len(resp_ie),
+ MULTI_LINK_CONTROL_TYPE_BASIC);
+ if (!ml_ie)
+ return;
+
+ drv->mlo_assoc_link_id = nl80211_get_assoc_link_id(&ml_ie[3],
+ ml_ie[1] - 1);
+ if (drv->mlo_assoc_link_id < 0 ||
+ drv->mlo_assoc_link_id >= MAX_NUM_MLD_LINKS)
+ return;
+
+ os_memcpy(mlo->ap_mld_addr, nla_data(addr), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: AP MLD MAC Address " MACSTR,
+ MAC2STR(mlo->ap_mld_addr));
+
+ if (!qca_roam_auth)
+ nl80211_parse_mlo_link_info(mlo, mlo_links);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (qca_roam_auth)
+ nl80211_parse_qca_vendor_mlo_link_info(mlo, mlo_links);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+ if (!(mlo->valid_links & BIT(drv->mlo_assoc_link_id))) {
+ wpa_printf(MSG_ERROR, "nl80211: Invalid MLO assoc link ID %d",
+ drv->mlo_assoc_link_id);
+ mlo->valid_links = 0;
+ return;
+ }
+
+ os_memcpy(drv->bssid, mlo->links[drv->mlo_assoc_link_id].bssid,
+ ETH_ALEN);
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+}
+
+
static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *status,
+ enum nl80211_commands cmd, bool qca_roam_auth,
+ struct nlattr *status,
struct nlattr *addr, struct nlattr *req_ie,
struct nlattr *resp_ie,
struct nlattr *timed_out,
@@ -430,7 +571,8 @@
struct nlattr *subnet_status,
struct nlattr *fils_erp_next_seq_num,
struct nlattr *fils_pmk,
- struct nlattr *fils_pmkid)
+ struct nlattr *fils_pmkid,
+ struct nlattr *mlo_links)
{
union wpa_event_data event;
const u8 *ssid = NULL;
@@ -522,7 +664,9 @@
}
drv->associated = 1;
- if (addr) {
+ drv->sta_mlo_info.valid_links = 0;
+ nl80211_parse_mlo_info(drv, qca_roam_auth, addr, mlo_links, resp_ie);
+ if (!drv->sta_mlo_info.valid_links && addr) {
os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
}
@@ -673,6 +817,9 @@
case CHAN_WIDTH_80P80:
freq1 = cf1 - 30;
break;
+ case CHAN_WIDTH_320:
+ freq1 = cf1 - 150;
+ break;
case CHAN_WIDTH_UNKNOWN:
case CHAN_WIDTH_2160:
case CHAN_WIDTH_4320:
@@ -687,10 +834,10 @@
static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *ifindex, struct nlattr *freq,
- struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2,
- int finished)
+ struct nlattr *ifindex, struct nlattr *link,
+ struct nlattr *freq, struct nlattr *type,
+ struct nlattr *bw, struct nlattr *cf1,
+ struct nlattr *cf2, int finished)
{
struct i802_bss *bss;
union wpa_event_data data;
@@ -754,6 +901,25 @@
if (finished)
bss->freq = data.ch_switch.freq;
+
+ if (link) {
+ u8 link_id = nla_get_u8(link);
+
+ if (link_id < MAX_NUM_MLD_LINKS &&
+ drv->sta_mlo_info.valid_links & BIT(link_id)) {
+ data.ch_switch.link_id = link_id;
+ drv->sta_mlo_info.links[link_id].freq =
+ data.ch_switch.freq;
+ wpa_supplicant_event(
+ bss->ctx,
+ finished ? EVENT_LINK_CH_SWITCH :
+ EVENT_LINK_CH_SWITCH_STARTED, &data);
+ }
+
+ if (link_id != drv->mlo_assoc_link_id)
+ return;
+ }
+
drv->assoc_freq = data.ch_switch.freq;
wpa_supplicant_event(bss->ctx, finished ?
@@ -1080,6 +1246,7 @@
struct nlattr *wmm, struct nlattr *req_ie)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ u16 stype = 0, auth_type = 0;
const u8 *data;
size_t len;
@@ -1109,11 +1276,31 @@
nl80211_command_to_string(cmd), bss->ifname,
MAC2STR(bss->addr), MAC2STR(data + 4),
MAC2STR(data + 4 + ETH_ALEN));
- if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
- os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
- (is_zero_ether_addr(bss->rand_addr) ||
- os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
- os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+
+ /* PASN Authentication frame can be received with a different source MAC
+ * address. Allow NL80211_CMD_FRAME event with foreign addresses also.
+ */
+ if (cmd == NL80211_CMD_FRAME && len >= 24) {
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ mgmt = (const struct ieee80211_mgmt *) data;
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+ auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ }
+
+ if (cmd == NL80211_CMD_FRAME && stype == WLAN_FC_STYPE_AUTH &&
+ auth_type == host_to_le16(WLAN_AUTH_PASN)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: %s: Allow PASN frame for foreign address",
+ bss->ifname);
+ } else if (cmd != NL80211_CMD_FRAME_TX_STATUS &&
+ !(data[4] & 0x01) &&
+ os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ (is_zero_ether_addr(bss->rand_addr) ||
+ os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
+ os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
"for foreign address", bss->ifname);
return;
@@ -1490,7 +1677,7 @@
* nl80211_get_link_signal() and nl80211_get_link_noise() set default
* values in case querying the driver fails.
*/
- res = nl80211_get_link_signal(drv, &ed.signal_change);
+ res = nl80211_get_link_signal(drv, drv->bssid, &ed.signal_change);
if (res == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
ed.signal_change.current_signal,
@@ -2092,7 +2279,7 @@
bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]);
wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid));
- mlme_event_connect(drv, NL80211_CMD_ROAM, NULL,
+ mlme_event_connect(drv, NL80211_CMD_ROAM, true, NULL,
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
@@ -2104,7 +2291,8 @@
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK],
- tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID]);
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS]);
}
@@ -2115,7 +2303,6 @@
if (!drv->roam_indication_done) {
wpa_printf(MSG_DEBUG,
"nl80211: Pending roam indication, delay processing roam+auth vendor event");
- os_get_reltime(&drv->pending_roam_ind_time);
os_free(drv->pending_roam_data);
drv->pending_roam_data = os_memdup(data, len);
@@ -2371,6 +2558,82 @@
wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
}
+
+#ifdef CONFIG_PASN
+
+static void qca_nl80211_pasn_auth(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ int ret = -EINVAL;
+ struct nlattr *attr;
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ struct nlattr *cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1];
+ unsigned int n_peers = 0, idx = 0;
+ int rem_conf;
+ enum qca_wlan_vendor_pasn_action action;
+ union wpa_event_data event;
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PASN_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]) {
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ action = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]);
+ switch (action) {
+ case QCA_WLAN_VENDOR_PASN_ACTION_AUTH:
+ event.pasn_auth.action = PASN_ACTION_AUTH;
+ break;
+ case QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT:
+ event.pasn_auth.action =
+ PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT;
+ break;
+ default:
+ return;
+ }
+
+ nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], rem_conf)
+ n_peers++;
+
+ if (n_peers > WPAS_MAX_PASN_PEERS) {
+ wpa_printf(MSG_DEBUG, "nl80211: PASN auth: too many peers (%d)",
+ n_peers);
+ return;
+ }
+
+ nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS],
+ rem_conf) {
+ struct nlattr *nl_src, *nl_peer;
+
+ ret = nla_parse_nested(cfg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX,
+ attr, NULL);
+ if (ret)
+ return;
+ nl_src = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR];
+ nl_peer = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR];
+ if (nl_src)
+ os_memcpy(event.pasn_auth.peer[idx].own_addr, nl_src,
+ ETH_ALEN);
+ if (nl_peer)
+ os_memcpy(event.pasn_auth.peer[idx].peer_addr, nl_peer,
+ ETH_ALEN);
+ if (cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED])
+ event.pasn_auth.peer[idx].ltf_keyseed_required = true;
+ idx++;
+ }
+ event.pasn_auth.num_peers = n_peers;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: PASN auth action: %u, num_bssids: %d",
+ event.pasn_auth.action,
+ event.pasn_auth.num_peers);
+ wpa_supplicant_event(drv->ctx, EVENT_PASN_AUTH, &event);
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -2407,6 +2670,11 @@
case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
qca_nl80211_p2p_lo_stop_event(drv, data, len);
break;
+#ifdef CONFIG_PASN
+ case QCA_NL80211_VENDOR_SUBCMD_PASN:
+ qca_nl80211_pasn_auth(drv, data, len);
+ break;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_DRIVER_NL80211_QCA */
default:
wpa_printf(MSG_DEBUG,
@@ -2789,6 +3057,9 @@
case NL80211_CHAN_WIDTH_160:
ed.sta_opmode.chan_width = CHAN_WIDTH_160;
break;
+ case NL80211_CHAN_WIDTH_320:
+ ed.sta_opmode.chan_width = CHAN_WIDTH_320;
+ break;
default:
ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN;
break;
@@ -2808,6 +3079,7 @@
{
u8 *src_addr;
u16 ethertype;
+ enum frame_encryption encrypted;
if (!tb[NL80211_ATTR_MAC] ||
!tb[NL80211_ATTR_FRAME] ||
@@ -2816,6 +3088,8 @@
src_addr = nla_data(tb[NL80211_ATTR_MAC]);
ethertype = nla_get_u16(tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+ encrypted = nla_get_flag(tb[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) ?
+ FRAME_NOT_ENCRYPTED : FRAME_ENCRYPTED;
switch (ethertype) {
case ETH_P_RSN_PREAUTH:
@@ -2824,9 +3098,10 @@
MAC2STR(src_addr));
break;
case ETH_P_PAE:
- drv_event_eapol_rx(drv->ctx, src_addr,
- nla_data(tb[NL80211_ATTR_FRAME]),
- nla_len(tb[NL80211_ATTR_FRAME]));
+ drv_event_eapol_rx2(drv->ctx, src_addr,
+ nla_data(tb[NL80211_ATTR_FRAME]),
+ nla_len(tb[NL80211_ATTR_FRAME]),
+ encrypted);
break;
default:
wpa_printf(MSG_INFO,
@@ -2923,8 +3198,8 @@
data.bss_color_collision.bitmap =
nla_get_u64(tb[NL80211_ATTR_OBSS_COLOR_BITMAP]);
- wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08lx",
- data.bss_color_collision.bitmap);
+ wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx",
+ (long long unsigned int) data.bss_color_collision.bitmap);
wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data);
}
@@ -2975,17 +3250,10 @@
if (cmd == NL80211_CMD_ROAM &&
(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
if (drv->pending_roam_data) {
- struct os_reltime now, age;
-
- os_get_reltime(&now);
- os_reltime_sub(&now, &drv->pending_roam_ind_time, &age);
- if (age.sec == 0 && age.usec < 100000) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Process pending roam+auth vendor event");
- qca_nl80211_key_mgmt_auth(
- drv, drv->pending_roam_data,
- drv->pending_roam_data_len);
- }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Process pending roam+auth vendor event");
+ qca_nl80211_key_mgmt_auth(drv, drv->pending_roam_data,
+ drv->pending_roam_data_len);
os_free(drv->pending_roam_data);
drv->pending_roam_data = NULL;
return;
@@ -3087,7 +3355,7 @@
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
- mlme_event_connect(drv, cmd,
+ mlme_event_connect(drv, cmd, false,
tb[NL80211_ATTR_STATUS_CODE],
tb[NL80211_ATTR_MAC],
tb[NL80211_ATTR_REQ_IE],
@@ -3099,11 +3367,13 @@
NULL,
tb[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM],
tb[NL80211_ATTR_PMK],
- tb[NL80211_ATTR_PMKID]);
+ tb[NL80211_ATTR_PMKID],
+ tb[NL80211_ATTR_MLO_LINKS]);
break;
case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY:
mlme_event_ch_switch(drv,
tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_MLO_LINK_ID],
tb[NL80211_ATTR_WIPHY_FREQ],
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
tb[NL80211_ATTR_CHANNEL_WIDTH],
@@ -3114,6 +3384,7 @@
case NL80211_CMD_CH_SWITCH_NOTIFY:
mlme_event_ch_switch(drv,
tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_MLO_LINK_ID],
tb[NL80211_ATTR_WIPHY_FREQ],
tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
tb[NL80211_ATTR_CHANNEL_WIDTH],
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index b82e5af..d54dd3a 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -203,6 +203,21 @@
goto fail;
}
nla_nest_end(msg, ssids);
+
+ /*
+ * If allowed, scan for 6 GHz APs that are reported by other
+ * APs. Note that if the flag is not set and 6 GHz channels are
+ * to be scanned, it is highly likely that non-PSC channels
+ * would be scanned passively (due to the Probe Request frame
+ * transmission restrictions mandated in IEEE Std 802.11ax-2021,
+ * 26.17.2.3 (Scanning in the 6 GHz band). Passive scanning of
+ * all non-PSC channels would take a significant amount of time.
+ */
+ if (!params->non_coloc_6ghz) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Scan co-located APs on 6 GHz");
+ scan_flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
+ }
} else {
wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
}
@@ -397,7 +412,7 @@
drv->scan_state = SCAN_REQUESTED;
/* Not all drivers generate "scan completed" wireless event, so try to
* read results after a timeout. */
- timeout = 10;
+ timeout = drv->uses_6ghz ? 15 : 10;
if (drv->scan_complete_events) {
/*
* The driver seems to deliver events to notify when scan is
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 0568a79..ffb7c57 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -324,6 +324,17 @@
*/
/**
+ * DOC: Multi-Link Operation
+ *
+ * In Multi-Link Operation, a connection between to MLDs utilizes multiple
+ * links. To use this in nl80211, various commands and responses now need
+ * to or will include the new %NL80211_ATTR_MLO_LINKS attribute.
+ * Additionally, various commands that need to operate on a specific link
+ * now need to be given the %NL80211_ATTR_MLO_LINK_ID attribute, e.g. to
+ * use %NL80211_CMD_START_AP or similar functions.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -753,6 +764,13 @@
* %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA
* counters which will be updated to the current value. This attribute
* is used during CSA period.
+ * For TX on an MLD, the frequency can be omitted and the link ID be
+ * specified, or if transmitting to a known peer MLD (with MLD addresses
+ * in the frame) both can be omitted and the link will be selected by
+ * lower layers.
+ * For RX notification, %NL80211_ATTR_RX_HW_TIMESTAMP may be included to
+ * indicate the frame RX timestamp and %NL80211_ATTR_TX_HW_TIMESTAMP may
+ * be included to indicate the ack TX timestamp.
* @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
* command may be used with the corresponding cookie to cancel the wait
* time if it is known that it is no longer necessary. This command is
@@ -763,7 +781,9 @@
* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
* the TX command and %NL80211_ATTR_FRAME includes the contents of the
* frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
- * the frame.
+ * the frame. %NL80211_ATTR_TX_HW_TIMESTAMP may be included to indicate the
+ * tx timestamp and %NL80211_ATTR_RX_HW_TIMESTAMP may be included to
+ * indicate the ack RX timestamp.
* @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
* backward compatibility.
*
@@ -1108,6 +1128,12 @@
* has been received. %NL80211_ATTR_FRAME is used to specify the
* frame contents. The frame is the raw EAPoL data, without ethernet or
* 802.11 headers.
+ * For an MLD transmitter, the %NL80211_ATTR_MLO_LINK_ID may be given and
+ * its effect will depend on the destination: If the destination is known
+ * to be an MLD, this will be used as a hint to select the link to transmit
+ * the frame on. If the destination is not an MLD, this will select both
+ * the link to transmit on and the source address will be set to the link
+ * address of that link.
* When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
* indicating the protocol type of the received frame; whether the frame
@@ -1237,6 +1263,16 @@
* to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to
* specify the timeout value.
*
+ * @NL80211_CMD_ADD_LINK: Add a new link to an interface. The
+ * %NL80211_ATTR_MLO_LINK_ID attribute is used for the new link.
+ * @NL80211_CMD_REMOVE_LINK: Remove a link from an interface. This may come
+ * without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links
+ * in preparation for e.g. roaming to a regular (non-MLO) AP.
+ *
+ * @NL80211_CMD_ADD_LINK_STA: Add a link to an MLD station
+ * @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station
+ * @NL80211_CMD_REMOVE_LINK_STA: Remove a link of an MLD station
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1481,6 +1517,13 @@
NL80211_CMD_ASSOC_COMEBACK,
+ NL80211_CMD_ADD_LINK,
+ NL80211_CMD_REMOVE_LINK,
+
+ NL80211_CMD_ADD_LINK_STA,
+ NL80211_CMD_MODIFY_LINK_STA,
+ NL80211_CMD_REMOVE_LINK_STA,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2340,8 +2383,10 @@
*
* @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
* %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
- * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
- * interface type.
+ * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities and
+ * other interface-type specific capabilities per interface type. For MLO,
+ * %NL80211_ATTR_EML_CAPABILITY and %NL80211_ATTR_MLD_CAPA_AND_OPS are
+ * present.
*
* @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO
* groupID for monitor mode.
@@ -2663,6 +2708,39 @@
* association request when used with NL80211_CMD_NEW_STATION). Can be set
* only if %NL80211_STA_FLAG_WME is set.
*
+ * @NL80211_ATTR_MLO_LINK_ID: A (u8) link ID for use with MLO, to be used with
+ * various commands that need a link ID to operate.
+ * @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some
+ * per-link information and a link ID.
+ * @NL80211_ATTR_MLD_ADDR: An MLD address, used with various commands such as
+ * authenticate/associate.
+ *
+ * @NL80211_ATTR_MLO_SUPPORT: Flag attribute to indicate user space supports MLO
+ * connection. Used with %NL80211_CMD_CONNECT. If this attribute is not
+ * included in NL80211_CMD_CONNECT drivers must not perform MLO connection.
+ *
+ * @NL80211_ATTR_MAX_NUM_AKM_SUITES: U16 attribute. Indicates maximum number of
+ * AKM suites allowed for %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and
+ * %NL80211_CMD_START_AP in %NL80211_CMD_GET_WIPHY response. If this
+ * attribute is not present userspace shall consider maximum number of AKM
+ * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum
+ * number prior to the introduction of this attribute.
+ *
+ * @NL80211_ATTR_EML_CAPABILITY: EML Capability information (u16)
+ * @NL80211_ATTR_MLD_CAPA_AND_OPS: MLD Capabilities and Operations (u16)
+ *
+ * @NL80211_ATTR_TX_HW_TIMESTAMP: Hardware timestamp for TX operation in
+ * nanoseconds (u64). This is the device clock timestamp so it will
+ * probably reset when the device is stopped or the firmware is reset.
+ * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the frame TX
+ * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates
+ * the ack TX timestamp.
+ * @NL80211_ATTR_RX_HW_TIMESTAMP: Hardware timestamp for RX operation in
+ * nanoseconds (u64). This is the device clock timestamp so it will
+ * probably reset when the device is stopped or the firmware is reset.
+ * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the ack RX
+ * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates
+ * the incoming frame RX timestamp.
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3175,6 +3253,22 @@
NL80211_ATTR_EHT_CAPABILITY,
+ NL80211_ATTR_DISABLE_EHT,
+
+ NL80211_ATTR_MLO_LINKS,
+ NL80211_ATTR_MLO_LINK_ID,
+ NL80211_ATTR_MLD_ADDR,
+
+ NL80211_ATTR_MLO_SUPPORT,
+
+ NL80211_ATTR_MAX_NUM_AKM_SUITES,
+
+ NL80211_ATTR_EML_CAPABILITY,
+ NL80211_ATTR_MLD_CAPA_AND_OPS,
+
+ NL80211_ATTR_TX_HW_TIMESTAMP,
+ NL80211_ATTR_RX_HW_TIMESTAMP,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3229,6 +3323,11 @@
#define NL80211_HE_MIN_CAPABILITY_LEN 16
#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
+
+/*
+ * NL80211_MAX_NR_AKM_SUITES is obsolete when %NL80211_ATTR_MAX_NUM_AKM_SUITES
+ * present in %NL80211_CMD_GET_WIPHY response.
+ */
#define NL80211_MAX_NR_AKM_SUITES 2
#define NL80211_EHT_MIN_CAPABILITY_LEN 13
#define NL80211_EHT_MAX_CAPABILITY_LEN 51
@@ -4851,6 +4950,7 @@
* Contains a nested array of signal strength attributes (u8, dBm),
* using the nesting index as the antenna number.
* @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz
+ * @NL80211_BSS_MLO_LINK_ID: MLO link ID of the BSS (u8).
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -4876,6 +4976,7 @@
NL80211_BSS_PARENT_BSSID,
NL80211_BSS_CHAIN_SIGNAL,
NL80211_BSS_FREQUENCY_OFFSET,
+ NL80211_BSS_MLO_LINK_ID,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -5872,7 +5973,7 @@
* @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
* the connected inactive stations in AP mode.
* @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
- * to work properly to suppport receiving regulatory hints from
+ * to work properly to support receiving regulatory hints from
* cellular base stations.
* @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: (no longer available, only
* here to reserve the value for API/ABI compatibility)
diff --git a/src/eap_common/eap_sake_common.c b/src/eap_common/eap_sake_common.c
index 8ee9e32..a4256e2 100644
--- a/src/eap_common/eap_sake_common.c
+++ b/src/eap_common/eap_sake_common.c
@@ -164,26 +164,33 @@
os_memset(attr, 0, sizeof(*attr));
while (pos < end) {
+ u8 attr_id, attr_len;
+
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
return -1;
}
- if (pos[1] < 2) {
- wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
- "length (%d)", pos[1]);
+ attr_id = *pos++;
+ attr_len = *pos++;
+ /* Attribute length value includes the Type and Length fields */
+ if (attr_len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SAKE: Invalid attribute length (%d)",
+ attr_len);
return -1;
}
+ attr_len -= 2;
- if (pos + pos[1] > end) {
+ if (attr_len > end - pos) {
wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
return -1;
}
- if (eap_sake_parse_add_attr(attr, pos[0], pos[1] - 2, pos + 2))
+ if (eap_sake_parse_add_attr(attr, attr_id, attr_len, pos))
return -1;
- pos += pos[1];
+ pos += attr_len;
}
return 0;
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 269d719..db46d95 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1707,7 +1707,7 @@
identity_len = config->machine_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
identity, identity_len);
- } else if (config->imsi_privacy_key && config->identity &&
+ } else if (config->imsi_privacy_cert && config->identity &&
config->identity_len > 0) {
const u8 *pos = config->identity;
const u8 *end = config->identity + config->identity_len;
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index e721efe..7f660e6 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -103,20 +103,20 @@
data->eap_method = EAP_TYPE_AKA;
- if (config && config->imsi_privacy_key) {
+ if (config && config->imsi_privacy_cert) {
#ifdef CRYPTO_RSA_OAEP_SHA256
data->imsi_privacy_key = crypto_rsa_key_read(
- config->imsi_privacy_key, false);
+ config->imsi_privacy_cert, false);
if (!data->imsi_privacy_key) {
wpa_printf(MSG_ERROR,
- "EAP-AKA: Failed to read/parse IMSI privacy key %s",
- config->imsi_privacy_key);
+ "EAP-AKA: Failed to read/parse IMSI privacy certificate %s",
+ config->imsi_privacy_cert);
os_free(data);
return NULL;
}
#else /* CRYPTO_RSA_OAEP_SHA256 */
wpa_printf(MSG_ERROR,
- "EAP-AKA: No support for imsi_privacy_key in the build");
+ "EAP-AKA: No support for imsi_privacy_cert in the build");
os_free(data);
return NULL;
#endif /* CRYPTO_RSA_OAEP_SHA256 */
@@ -639,11 +639,12 @@
#ifdef CRYPTO_RSA_OAEP_SHA256
static struct wpabuf *
eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
- const u8 *identity, size_t identity_len)
+ const u8 *identity, size_t identity_len,
+ const char *attr)
{
struct wpabuf *imsi_buf, *enc;
char *b64;
- size_t b64_len;
+ size_t b64_len, len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity",
identity, identity_len);
@@ -661,7 +662,10 @@
if (!b64)
return NULL;
- enc = wpabuf_alloc(1 + b64_len);
+ len = 1 + b64_len;
+ if (attr)
+ len += 1 + os_strlen(attr);
+ enc = wpabuf_alloc(len);
if (!enc) {
os_free(b64);
return NULL;
@@ -669,6 +673,10 @@
wpabuf_put_u8(enc, '\0');
wpabuf_put_data(enc, b64, b64_len);
os_free(b64);
+ if (attr) {
+ wpabuf_put_u8(enc, ',');
+ wpabuf_put_str(enc, attr);
+ }
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity",
wpabuf_head(enc), wpabuf_len(enc));
@@ -712,9 +720,15 @@
}
#ifdef CRYPTO_RSA_OAEP_SHA256
if (identity && data->imsi_privacy_key) {
+ struct eap_peer_config *config;
+ const char *attr = NULL;
+
+ config = eap_get_config(sm);
+ if (config)
+ attr = config->imsi_privacy_attr;
enc_identity = eap_aka_encrypt_identity(
data->imsi_privacy_key,
- identity, identity_len);
+ identity, identity_len, attr);
if (!enc_identity) {
wpa_printf(MSG_INFO,
"EAP-AKA: Failed to encrypt permanent identity");
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index eaf514b..26744ab 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -318,14 +318,24 @@
size_t imsi_identity_len;
/**
- * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+ * imsi_privacy_cert - IMSI privacy certificate
*
* This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
- * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
- * include a 2048-bit RSA public key and this is from the operator who
- * authenticates the SIM/USIM.
+ * identity (IMSI) to improve privacy. The referenced PEM-encoded
+ * X.509v3 certificate needs to include a 2048-bit RSA public key and
+ * this is from the operator who authenticates the SIM/USIM.
*/
- char *imsi_privacy_key;
+ char *imsi_privacy_cert;
+
+ /**
+ * imsi_privacy_attr - IMSI privacy attribute
+ *
+ * This field is used to help the EAP-SIM/AKA/AKA' server to identify
+ * the used certificate (and as such, the matching private key). This
+ * is set to an attribute in name=value format if the operator needs
+ * this information.
+ */
+ char *imsi_privacy_attr;
/**
* machine_identity - EAP Identity for machine credential
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 954c585..71e9108 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -101,20 +101,20 @@
return NULL;
}
- if (config && config->imsi_privacy_key) {
+ if (config && config->imsi_privacy_cert) {
#ifdef CRYPTO_RSA_OAEP_SHA256
data->imsi_privacy_key = crypto_rsa_key_read(
- config->imsi_privacy_key, false);
+ config->imsi_privacy_cert, false);
if (!data->imsi_privacy_key) {
wpa_printf(MSG_ERROR,
- "EAP-SIM: Failed to read/parse IMSI privacy key %s",
- config->imsi_privacy_key);
+ "EAP-SIM: Failed to read/parse IMSI privacy certificate %s",
+ config->imsi_privacy_cert);
os_free(data);
return NULL;
}
#else /* CRYPTO_RSA_OAEP_SHA256 */
wpa_printf(MSG_ERROR,
- "EAP-SIM: No support for imsi_privacy_key in the build");
+ "EAP-SIM: No support for imsi_privacy_cert in the build");
os_free(data);
return NULL;
#endif /* CRYPTO_RSA_OAEP_SHA256 */
@@ -133,6 +133,9 @@
"sim_min_num_chal configuration "
"(%lu, expected 2 or 3)",
(unsigned long) data->min_num_chal);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
return NULL;
}
@@ -504,11 +507,12 @@
#ifdef CRYPTO_RSA_OAEP_SHA256
static struct wpabuf *
eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
- const u8 *identity, size_t identity_len)
+ const u8 *identity, size_t identity_len,
+ const char *attr)
{
struct wpabuf *imsi_buf, *enc;
char *b64;
- size_t b64_len;
+ size_t b64_len, len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
identity, identity_len);
@@ -526,7 +530,10 @@
if (!b64)
return NULL;
- enc = wpabuf_alloc(1 + b64_len);
+ len = 1 + b64_len;
+ if (attr)
+ len += 1 + os_strlen(attr);
+ enc = wpabuf_alloc(len);
if (!enc) {
os_free(b64);
return NULL;
@@ -534,6 +541,10 @@
wpabuf_put_u8(enc, '\0');
wpabuf_put_data(enc, b64, b64_len);
os_free(b64);
+ if (attr) {
+ wpabuf_put_u8(enc, ',');
+ wpabuf_put_str(enc, attr);
+ }
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
wpabuf_head(enc), wpabuf_len(enc));
@@ -577,9 +588,15 @@
}
#ifdef CRYPTO_RSA_OAEP_SHA256
if (identity && data->imsi_privacy_key) {
+ struct eap_peer_config *config;
+ const char *attr = NULL;
+
+ config = eap_get_config(sm);
+ if (config)
+ attr = config->imsi_privacy_attr;
enc_identity = eap_sim_encrypt_identity(
data->imsi_privacy_key,
- identity, identity_len);
+ identity, identity_len, attr);
if (!enc_identity) {
wpa_printf(MSG_INFO,
"EAP-SIM: Failed to encrypt permanent identity");
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 4e66369..6173960 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1281,11 +1281,12 @@
* @src: Source MAC address of the EAPOL packet
* @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
* @len: Length of the EAPOL frame
+ * @encrypted: Whether the frame was encrypted
* Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
* -1 failure
*/
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
- size_t len)
+ size_t len, enum frame_encryption encrypted)
{
const struct ieee802_1x_hdr *hdr;
const struct ieee802_1x_eapol_key *key;
@@ -1295,6 +1296,14 @@
if (sm == NULL)
return 0;
+
+ if (encrypted == FRAME_NOT_ENCRYPTED && sm->ctx->encryption_required &&
+ sm->ctx->encryption_required(sm->ctx->ctx)) {
+ wpa_printf(MSG_DEBUG,
+ "EAPOL: Discard unencrypted EAPOL frame when encryption since encryption was expected");
+ return 0;
+ }
+
sm->dot1xSuppEapolFramesRx++;
if (len < sizeof(*hdr)) {
sm->dot1xSuppInvalidEapolFramesRx++;
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 630a38e..bbe2b6f 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -321,6 +321,13 @@
* @reason_string: Information to log about the event
*/
void (*open_ssl_failure_cb)(void *ctx, const char* reason_string);
+
+ /**
+ * encryption_required - Check whether encryption is required
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * Returns: Whether the current session requires encryption
+ */
+ bool (*encryption_required)(void *ctx);
};
@@ -337,7 +344,7 @@
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int startPeriod, int maxStart);
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
- size_t len);
+ size_t len, enum frame_encryption encrypted);
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled);
void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid);
@@ -403,7 +410,8 @@
{
}
static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
return 0;
}
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index d1c4014..255d0fd 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -28,8 +28,13 @@
while (s >= 2) {
const struct multi_band_ie *mbie =
(const struct multi_band_ie *) p;
+ size_t len;
+
WPA_ASSERT(mbie->eid == WLAN_EID_MULTI_BAND);
WPA_ASSERT(2U + mbie->len >= sizeof(*mbie));
+ len = 2 + mbie->len;
+ if (len > s)
+ break;
fst_printf(MSG_WARNING,
"%s: %s: mb_ctrl=%u band_id=%u op_class=%u chan=%u bssid="
@@ -45,8 +50,8 @@
mbie->mb_connection_capability,
mbie->fst_session_tmout);
- p += 2 + mbie->len;
- s -= 2 + mbie->len;
+ p += len;
+ s -= len;
}
}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index cd04008..b7fde1b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1803,6 +1803,7 @@
os_memcpy(params->passphrase, p2p->passphrase, os_strlen(p2p->passphrase));
} else {
p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+ params->passphrase[p2p->cfg->passphrase_len] = '\0';
}
p2p->passphrase_set = 0;
return 0;
@@ -1837,6 +1838,7 @@
os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
res.ssid_len = p2p->ssid_len;
p2p_random(res.passphrase, p2p->cfg->passphrase_len);
+ res.passphrase[p2p->cfg->passphrase_len] = '\0';
} else {
res.freq = peer->oper_freq;
if (p2p->ssid_len) {
@@ -5540,7 +5542,7 @@
void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
- const unsigned int *pref_freq_list,
+ const struct weighted_pcl *pref_freq_list,
unsigned int size)
{
unsigned int i;
@@ -5548,10 +5550,11 @@
if (size > P2P_MAX_PREF_CHANNELS)
size = P2P_MAX_PREF_CHANNELS;
p2p->num_pref_freq = size;
+ os_memcpy(p2p->pref_freq_list, pref_freq_list,
+ size * sizeof(struct weighted_pcl));
for (i = 0; i < size; i++) {
- p2p->pref_freq_list[i] = pref_freq_list[i];
p2p_dbg(p2p, "Own preferred frequency list[%u]=%u MHz",
- i, p2p->pref_freq_list[i]);
+ i, p2p->pref_freq_list[i].freq);
}
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index f606fbb..27bdac3 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -12,6 +12,8 @@
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+struct weighted_pcl;
+
/* P2P ASP Setup Capability */
#define P2PS_SETUP_NONE 0
#define P2PS_SETUP_NEW BIT(0)
@@ -1132,7 +1134,8 @@
* the driver specific to a particular interface type.
*/
int (*get_pref_freq_list)(void *ctx, int go,
- unsigned int *len, unsigned int *freq_list);
+ unsigned int *len,
+ struct weighted_pcl *freq_list);
};
@@ -2338,6 +2341,8 @@
const u8 *go_dev_addr,
const u8 *ssid, size_t ssid_len);
+bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go);
+
struct p2p_nfc_params {
int sel;
const u8 *wsc_attr;
@@ -2397,7 +2402,7 @@
void p2p_expire_peers(struct p2p_data *p2p);
void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
- const unsigned int *pref_freq_list,
+ const struct weighted_pcl *pref_freq_list,
unsigned int size);
void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
u8 chan);
@@ -2422,6 +2427,7 @@
bool p2p_wfd_enabled(struct p2p_data *p2p);
bool is_p2p_allow_6ghz(struct p2p_data *p2p);
void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value);
-int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size);
+int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size);
+int p2p_channel_to_freq(int op_class, int channel);
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 4229d9b..e4f40fe 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/qca-vendor.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
@@ -111,7 +112,7 @@
void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
- const unsigned int *preferred_freq_list,
+ const struct weighted_pcl *pref_freq_list,
unsigned int size)
{
unsigned int i, count = 0;
@@ -126,8 +127,9 @@
* of the vendor IE size.
*/
for (i = 0; i < size; i++) {
- if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
- &op_channel) == 0)
+ if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class,
+ &op_channel) == 0 &&
+ !(pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE))
count++;
}
@@ -136,10 +138,11 @@
wpabuf_put_be24(buf, OUI_QCA);
wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST);
for (i = 0; i < size; i++) {
- if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
- &op_channel) < 0) {
+ if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class,
+ &op_channel) < 0 ||
+ (pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) {
wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz",
- preferred_freq_list[i]);
+ pref_freq_list[i].freq);
continue;
}
wpabuf_put_u8(buf, op_class);
@@ -149,7 +152,7 @@
void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
- struct p2p_channels *chan)
+ struct p2p_channels *chan, bool is_6ghz_capab)
{
u8 *len;
size_t i;
@@ -161,6 +164,9 @@
for (i = 0; i < chan->reg_classes; i++) {
struct p2p_reg_class *c = &chan->reg_class[i];
+
+ if (is_6ghz_op_class(c->reg_class) && !is_6ghz_capab)
+ continue;
wpabuf_put_u8(buf, c->reg_class);
wpabuf_put_u8(buf, c->channels);
wpabuf_put_data(buf, c->channel, c->channels);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 1d53d52..e3d704b 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -142,6 +142,7 @@
u8 group_capab;
size_t extra = 0;
u16 pw_id;
+ bool is_6ghz_capab;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -179,7 +180,22 @@
p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
p2p->ext_listen_interval);
p2p_buf_add_intended_addr(buf, p2p->intended_addr);
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+ if (p2p->num_pref_freq) {
+ bool go = p2p->go_intent == 15;
+ struct p2p_channels pref_chanlist;
+
+ p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list,
+ p2p->num_pref_freq, &pref_chanlist, go);
+ p2p_channels_dump(p2p, "channel list after filtering",
+ &pref_chanlist);
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &pref_chanlist, is_6ghz_capab);
+ } else {
+ p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ &p2p->channels, is_6ghz_capab);
+ }
p2p_buf_add_device_info(buf, p2p, peer);
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
p2p->op_reg_class, p2p->op_channel);
@@ -278,6 +294,8 @@
u8 group_capab;
size_t extra = 0;
u16 pw_id;
+ bool is_6ghz_capab;
+ struct p2p_channels pref_chanlist;
p2p_dbg(p2p, "Building GO Negotiation Response");
@@ -328,17 +346,35 @@
p2p->op_channel);
}
p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+ if (p2p->num_pref_freq) {
+ bool go = (peer && peer->go_state == LOCAL_GO) ||
+ p2p->go_intent == 15;
+
+ p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list,
+ p2p->num_pref_freq, &pref_chanlist, go);
+ p2p_channels_dump(p2p, "channel list after filtering",
+ &pref_chanlist);
+ } else {
+ p2p_copy_channels(&pref_chanlist, &p2p->channels,
+ p2p->allow_6ghz);
+ }
if (status || peer == NULL) {
p2p_buf_add_channel_list(buf, p2p->cfg->country,
- &p2p->channels);
+ &pref_chanlist, false);
} else if (peer->go_state == REMOTE_GO) {
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
p2p_buf_add_channel_list(buf, p2p->cfg->country,
- &p2p->channels);
+ &pref_chanlist, is_6ghz_capab);
} else {
struct p2p_channels res;
- p2p_channels_intersect(&p2p->channels, &peer->channels,
+
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+ p2p_channels_intersect(&pref_chanlist, &peer->channels,
&res);
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &res,
+ is_6ghz_capab);
}
p2p_buf_add_device_info(buf, p2p, peer);
if (peer && peer->go_state == LOCAL_GO) {
@@ -562,7 +598,8 @@
static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
struct p2p_device *dev,
struct p2p_message *msg,
- unsigned freq_list[], unsigned int size)
+ const struct weighted_pcl freq_list[],
+ unsigned int size)
{
u8 op_class, op_channel;
unsigned int oper_freq = 0, i, j;
@@ -577,10 +614,11 @@
*/
for (i = 0; i < size && !found; i++) {
/* Make sure that the common frequency is supported by peer. */
- oper_freq = freq_list[i];
+ oper_freq = freq_list[i].freq;
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0)
- continue; /* cannot happen due to earlier check */
+ &op_channel) < 0 ||
+ !p2p_pref_freq_allowed(&freq_list[i], go))
+ continue;
for (j = 0; j < msg->channel_list_len; j++) {
if (!msg->channel_list ||
op_channel != msg->channel_list[j])
@@ -609,7 +647,8 @@
static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go,
struct p2p_device *dev,
struct p2p_message *msg,
- unsigned freq_list[], unsigned int size)
+ const struct weighted_pcl freq_list[],
+ unsigned int size)
{
u8 op_class, op_channel;
unsigned int oper_freq = 0, i, j;
@@ -625,11 +664,13 @@
oper_freq = p2p_channel_to_freq(
msg->pref_freq_list[2 * j],
msg->pref_freq_list[2 * j + 1]);
- if (freq_list[i] != oper_freq)
+ if (freq_list[i].freq != oper_freq)
continue;
if (p2p_freq_to_channel(oper_freq, &op_class,
&op_channel) < 0)
continue; /* cannot happen */
+ if (!p2p_pref_freq_allowed(&freq_list[i], go))
+ break;
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -652,7 +693,7 @@
void p2p_check_pref_chan(struct p2p_data *p2p, int go,
struct p2p_device *dev, struct p2p_message *msg)
{
- unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
+ unsigned int size;
unsigned int i;
u8 op_class, op_channel;
char txt[100], *pos, *end;
@@ -669,25 +710,30 @@
/* Obtain our preferred frequency list from driver based on P2P role. */
size = P2P_MAX_PREF_CHANNELS;
- if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
- freq_list))
+ if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go,
+ &p2p->num_pref_freq,
+ p2p->pref_freq_list))
+ return;
+ size = p2p->num_pref_freq;
+ if (!size)
return;
/* Filter out frequencies that are not acceptable for P2P use */
i = 0;
while (i < size) {
- if (p2p_freq_to_channel(freq_list[i], &op_class,
- &op_channel) < 0 ||
+ if (p2p_freq_to_channel(p2p->pref_freq_list[i].freq,
+ &op_class, &op_channel) < 0 ||
(!p2p_channels_includes(&p2p->cfg->channels,
op_class, op_channel) &&
(go || !p2p_channels_includes(&p2p->cfg->cli_channels,
op_class, op_channel)))) {
p2p_dbg(p2p,
"Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
- freq_list[i], go);
+ p2p->pref_freq_list[i].freq, go);
if (size - i - 1 > 0)
- os_memmove(&freq_list[i], &freq_list[i + 1],
+ os_memmove(&p2p->pref_freq_list[i],
+ &p2p->pref_freq_list[i + 1],
(size - i - 1) *
- sizeof(unsigned int));
+ sizeof(struct weighted_pcl));
size--;
continue;
}
@@ -699,7 +745,8 @@
pos = txt;
end = pos + sizeof(txt);
for (i = 0; i < size; i++) {
- res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+ res = os_snprintf(pos, end - pos, " %u",
+ p2p->pref_freq_list[i].freq);
if (os_snprintf_error(end - pos, res))
break;
pos += res;
@@ -713,11 +760,14 @@
* our preferred channel list.
*/
for (i = 0; i < size; i++) {
- if (freq_list[i] == (unsigned int) dev->oper_freq)
+ if (p2p->pref_freq_list[i].freq ==
+ (unsigned int) dev->oper_freq &&
+ p2p_pref_freq_allowed(&p2p->pref_freq_list[i], go))
break;
}
if (i != size &&
- p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
+ p2p_freq_to_channel(p2p->pref_freq_list[i].freq, &op_class,
+ &op_channel) == 0) {
/* Peer operating channel preference matches our preference */
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
@@ -735,9 +785,11 @@
* _not_ included in the GO Negotiation Request or Invitation Request.
*/
if (msg->pref_freq_list_len == 0)
- p2p_check_pref_chan_no_recv(p2p, go, dev, msg, freq_list, size);
+ p2p_check_pref_chan_no_recv(p2p, go, dev, msg,
+ p2p->pref_freq_list, size);
else
- p2p_check_pref_chan_recv(p2p, go, dev, msg, freq_list, size);
+ p2p_check_pref_chan_recv(p2p, go, dev, msg,
+ p2p->pref_freq_list, size);
}
@@ -1085,6 +1137,7 @@
struct p2p_channels res;
u8 group_capab;
size_t extra = 0;
+ bool is_6ghz_capab;
p2p_dbg(p2p, "Building GO Negotiation Confirm");
@@ -1128,7 +1181,9 @@
p2p_buf_add_operating_channel(buf, (const char *) resp_chan,
resp_chan[3], resp_chan[4]);
p2p_channels_intersect(&p2p->channels, &peer->channels, &res);
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab);
if (go) {
p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
p2p->ssid_len);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index b5e5c2b..d8dc6f7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -10,6 +10,7 @@
#define P2P_I_H
#include "utils/list.h"
+#include "drivers/driver.h"
#include "p2p.h"
#include "ap/ap_config.h"
@@ -553,7 +554,7 @@
struct wpabuf **vendor_elem;
- unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
+ struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
unsigned int num_pref_freq;
/* Override option for preferred operating channel in GO Negotiation */
@@ -690,7 +691,6 @@
/* p2p_utils.c */
int p2p_random(char *buf, size_t len);
-int p2p_channel_to_freq(int op_class, int channel);
int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
@@ -769,7 +769,7 @@
void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
u8 reg_class, u8 channel);
void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
- struct p2p_channels *chan);
+ struct p2p_channels *chan, bool is_6ghz_capab);
void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
u8 client_timeout);
void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr);
@@ -800,7 +800,7 @@
int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
int all_attr);
void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
- const unsigned int *preferred_freq_list,
+ const struct weighted_pcl *pref_freq_list,
unsigned int size);
/* p2p_sd.c */
@@ -902,6 +902,10 @@
void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
u8 *status);
+void p2p_pref_channel_filter(const struct p2p_channels *a,
+ const struct weighted_pcl *freq_list,
+ unsigned int num_channels,
+ struct p2p_channels *res, bool go);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index ab00722..bca5b90 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -24,6 +24,7 @@
u8 *len;
const u8 *dev_addr;
size_t extra = 0;
+ bool is_6ghz_capab;
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
@@ -74,7 +75,10 @@
p2p->op_channel);
if (p2p->inv_bssid_set)
p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels,
+ is_6ghz_capab);
if (go_dev_addr)
dev_addr = go_dev_addr;
else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
@@ -155,8 +159,14 @@
reg_class, channel);
if (group_bssid)
p2p_buf_add_group_bssid(buf, group_bssid);
- if (channels)
- p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
+ if (channels) {
+ bool is_6ghz_capab;
+
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
+ p2p_buf_add_channel_list(buf, p2p->cfg->country, channels,
+ is_6ghz_capab);
+ }
p2p_buf_update_ie_hdr(buf, len);
#ifdef CONFIG_WIFI_DISPLAY
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 338b47e..1a78e14 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -124,9 +124,15 @@
}
if (shared_group ||
- (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW)))
+ (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) {
+ bool is_6ghz_capab;
+
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(
+ p2p, dev->info.p2p_device_addr);
p2p_buf_add_channel_list(buf, p2p->cfg->country,
- &p2p->channels);
+ &p2p->channels, is_6ghz_capab);
+ }
if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
(prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
@@ -356,9 +362,15 @@
}
if (persist ||
- (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
+ (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) {
+ bool is_6ghz_capab;
+
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(
+ p2p, dev->info.p2p_device_addr);
p2p_buf_add_channel_list(buf, p2p->cfg->country,
- &p2p->channels);
+ &p2p->channels, is_6ghz_capab);
+ }
if (!persist && conncap)
p2p_buf_add_connection_capability(buf, conncap);
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a203606..c1f0084 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -519,14 +519,14 @@
}
-int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size)
+int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size)
{
int i;
for (i = 0; i < size; i++) {
- if (is_6ghz_freq(pref_freq_list[i])) {
+ if (is_6ghz_freq(pref_freq_list[i].freq)) {
wpa_printf(MSG_DEBUG, "P2P: Remove 6 GHz channel %d",
- pref_freq_list[i]);
+ pref_freq_list[i].freq);
size--;
os_memmove(&pref_freq_list[i], &pref_freq_list[i + 1],
(size - i) * sizeof(pref_freq_list[0]));
@@ -535,3 +535,79 @@
}
return i;
}
+
+
+/**
+ * p2p_pref_freq_allowed - Based on the flags set, check if the preferred
+ * frequency is allowed
+ * @freq_list: Weighted preferred channel list
+ * @go: Whether the local device is the group owner
+ * Returns: Whether the preferred frequency is allowed
+ */
+bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go)
+{
+ if (freq_list->flag & WEIGHTED_PCL_EXCLUDE)
+ return false;
+ if (!(freq_list->flag & WEIGHTED_PCL_CLI) && !go)
+ return false;
+ if (!(freq_list->flag & WEIGHTED_PCL_GO) && go)
+ return false;
+ return true;
+}
+
+
+static int p2p_check_pref_channel(int channel, u8 op_class,
+ const struct weighted_pcl *freq_list,
+ unsigned int num_channels, bool go)
+{
+ unsigned int i;
+
+ /* If the channel is present in the preferred channel list, check if it
+ * has appropriate flags for the role.
+ */
+ for (i = 0; i < num_channels; i++) {
+ if (p2p_channel_to_freq(op_class, channel) !=
+ (int) freq_list[i].freq)
+ continue;
+ if (!p2p_pref_freq_allowed(&freq_list[i], go))
+ return -1;
+ break;
+ }
+
+ return 0;
+}
+
+
+void p2p_pref_channel_filter(const struct p2p_channels *p2p_chan,
+ const struct weighted_pcl *freq_list,
+ unsigned int num_channels,
+ struct p2p_channels *res, bool go)
+{
+ size_t i, j;
+
+ os_memset(res, 0, sizeof(*res));
+
+ for (i = 0; i < p2p_chan->reg_classes; i++) {
+ const struct p2p_reg_class *reg = &p2p_chan->reg_class[i];
+ struct p2p_reg_class *res_reg = &res->reg_class[i];
+
+ if (num_channels > 0) {
+ for (j = 0; j < reg->channels; j++) {
+ if (p2p_check_pref_channel(reg->channel[j],
+ reg->reg_class,
+ freq_list,
+ num_channels,
+ go) < 0)
+ continue;
+
+ res_reg->channel[res_reg->channels++] =
+ reg->channel[j];
+ }
+ }
+
+ if (res_reg->channels == 0)
+ continue;
+ res->reg_classes++;
+ res_reg->reg_class = reg->reg_class;
+ }
+}
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 1a38bf6..a96655f 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -75,7 +75,8 @@
return;
}
- eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
+ eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len,
+ FRAME_ENCRYPTION_UNKNOWN);
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 00b7e84..21f8b5b 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -187,7 +187,7 @@
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
- wpa_sm_get_state(sm) == WPA_COMPLETED) {
+ wpa_sm_get_state(sm) == WPA_COMPLETED && !error) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: PTK0 rekey not allowed, reconnecting");
wpa_sm_reconnect(sm);
@@ -302,7 +302,8 @@
#ifdef CONFIG_IEEE80211R
sm->xxkey_len = 0;
#ifdef CONFIG_SAE
- if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE &&
+ if ((sm->key_mgmt == WPA_KEY_MGMT_FT_SAE ||
+ sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) &&
sm->pmk_len == PMK_LEN) {
/* Need to allow FT key derivation to proceed with
* PMK from SAE being used as the XXKey in cases where
@@ -553,6 +554,8 @@
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = ver | WPA_KEY_INFO_KEY_TYPE;
+ if (sm->ptk_set && sm->proto != WPA_PROTO_WPA)
+ key_info |= WPA_KEY_INFO_SECURE;
if (mic_len)
key_info |= WPA_KEY_INFO_MIC;
else
@@ -583,6 +586,7 @@
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
+ int ret;
const u8 *z = NULL;
size_t z_len = 0, kdk_len;
int akmp;
@@ -616,11 +620,23 @@
else
kdk_len = 0;
- return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
- sm->own_addr, sm->bssid, sm->snonce,
- key->key_nonce, ptk, akmp,
- sm->pairwise_cipher, z, z_len,
- kdk_len);
+ ret = wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+ sm->own_addr, sm->bssid, sm->snonce,
+ key->key_nonce, ptk, akmp,
+ sm->pairwise_cipher, z, z_len,
+ kdk_len);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "WPA: PTK derivation failed");
+ return ret;
+ }
+
+#ifdef CONFIG_PASN
+ if (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
+ ret = wpa_ltf_keyseed(ptk, akmp, sm->pairwise_cipher);
+#endif /* CONFIG_PASN */
+
+ return ret;
}
@@ -673,7 +689,8 @@
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
u16 ver, const u8 *key_data,
- size_t key_data_len)
+ size_t key_data_len,
+ enum frame_encryption encrypted)
{
struct wpa_eapol_ie_parse ie;
struct wpa_ptk *ptk;
@@ -681,6 +698,13 @@
u8 *kde, *kde_buf = NULL;
size_t kde_len;
+ if (encrypted == FRAME_NOT_ENCRYPTED && sm->tk_set &&
+ wpa_sm_pmf_enabled(sm)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Discard unencrypted EAPOL-Key msg 1/4 when TK is set and PMF is enabled");
+ return;
+ }
+
if (wpa_sm_get_network_ctx(sm) == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
"found (msg 1 of 4)");
@@ -695,7 +719,6 @@
return;
}
- wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 1 of 4-Way "
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
@@ -705,8 +728,11 @@
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
key_data, key_data_len);
- if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
- goto failed;
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Discard EAPOL-Key msg 1/4 with invalid IEs/KDEs");
+ return;
+ }
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
"Authenticator", ie.pmkid, PMKID_LEN);
@@ -722,6 +748,8 @@
if (res)
goto failed;
+ wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+
if (sm->renew_snonce) {
if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -962,6 +990,20 @@
return -1;
}
+#ifdef CONFIG_PASN
+ if (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_sm_set_ltf_keyseed(sm, sm->own_addr, sm->bssid,
+ sm->ptk.ltf_keyseed_len,
+ sm->ptk.ltf_keyseed) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to set LTF keyseed to the driver (keylen=%zu bssid="
+ MACSTR ")", sm->ptk.ltf_keyseed_len,
+ MAC2STR(sm->bssid));
+ return -1;
+ }
+#endif /* CONFIG_PASN */
+
wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
@@ -969,6 +1011,7 @@
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
sm->ptk.tk_len = 0;
sm->ptk.installed = 1;
+ sm->tk_set = true;
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
@@ -2476,6 +2519,7 @@
* @src_addr: Source MAC address of the EAPOL packet
* @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
* @len: Length of the EAPOL frame
+ * @encrypted: Whether the frame was encrypted
* Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
*
* This function is called for each received EAPOL frame. Other than EAPOL-Key
@@ -2487,7 +2531,7 @@
* successful key handshake.
*/
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len, enum frame_encryption encrypted)
{
size_t plen, data_len, key_data_len;
const struct ieee802_1x_hdr *hdr;
@@ -2722,7 +2766,8 @@
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
ver, key_data,
- key_data_len);
+ key_data_len,
+ encrypted);
}
} else {
if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
@@ -3063,6 +3108,7 @@
os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep));
os_memset(&sm->igtk, 0, sizeof(sm->igtk));
os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep));
+ sm->tk_set = false;
}
#ifdef CONFIG_TDLS
@@ -3850,6 +3896,7 @@
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
sm->ptk_set = 0;
sm->tptk_set = 0;
+ sm->tk_set = false;
sm->pmk_len = 0;
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
@@ -3886,7 +3933,7 @@
{
if (!sm)
return 0;
- return sm->ptk.installed;
+ return sm->tk_set || sm->ptk.installed;
}
@@ -4474,6 +4521,15 @@
goto fail;
}
+#ifdef CONFIG_PASN
+ if (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_ltf_keyseed(&sm->ptk, sm->key_mgmt, sm->pairwise_cipher)) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive LTF keyseed");
+ goto fail;
+ }
+#endif /* CONFIG_PASN */
+
wpabuf_clear_free(dh_ss);
dh_ss = NULL;
@@ -5033,6 +5089,7 @@
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
sm->ptk.tk_len = 0;
sm->ptk.installed = 1;
+ sm->tk_set = true;
/* FILS HLP Container */
fils_process_hlp_container(sm, ie_start, end - ie_start);
@@ -5302,6 +5359,7 @@
#ifdef CONFIG_PASN
+
void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
const u8 *pmkid, const u8 *bssid, int key_mgmt)
{
@@ -5309,6 +5367,18 @@
bssid, sm->own_addr, NULL,
key_mgmt, 0);
}
+
+
+void wpa_pasn_sm_set_caps(struct wpa_sm *sm, unsigned int flags2)
+{
+ if (flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA)
+ sm->secure_ltf = 1;
+ if (flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA)
+ sm->secure_rtt = 1;
+ if (flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
+ sm->prot_range_neg = 1;
+}
+
#endif /* CONFIG_PASN */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 00fa0bc..411f328 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -19,6 +19,7 @@
struct wpa_config_blob;
struct hostapd_freq_params;
struct wpa_channel_info;
+enum frame_encryption;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -92,6 +93,11 @@
void (*transition_disable)(void *ctx, u8 bitmap);
void (*store_ptk)(void *ctx, u8 *addr, int cipher,
u32 life_time, const struct wpa_ptk *ptk);
+#ifdef CONFIG_PASN
+ int (*set_ltf_keyseed)(void *ctx, const u8 *own_addr,
+ const u8 *peer_addr, size_t ltf_keyseed_len,
+ const u8 *ltf_keyseed);
+#endif /* CONFIG_PASN */
};
@@ -184,7 +190,7 @@
void wpa_sm_aborted_cached(struct wpa_sm *sm);
void wpa_sm_aborted_external_cached(struct wpa_sm *sm);
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
- const u8 *buf, size_t len);
+ const u8 *buf, size_t len, enum frame_encryption encrypted);
int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm);
@@ -368,7 +374,8 @@
}
static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
return -1;
}
@@ -580,5 +587,6 @@
void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z);
void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
const u8 *pmkid, const u8 *bssid, int key_mgmt);
+void wpa_pasn_sm_set_caps(struct wpa_sm *sm, unsigned int flags2);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 9d3b538..96d293f 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -41,6 +41,7 @@
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *mpmk;
size_t mpmk_len, kdk_len;
+ int ret = 0;
if (sm->xxkey_len > 0) {
mpmk = sm->xxkey;
@@ -75,10 +76,22 @@
else
kdk_len = 0;
- return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
- sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
- ptk_name, sm->key_mgmt, sm->pairwise_cipher,
- kdk_len);
+ ret = wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
+ anonce, sm->own_addr, sm->bssid,
+ sm->pmk_r1_name, ptk, ptk_name, sm->key_mgmt,
+ sm->pairwise_cipher, kdk_len);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "FT: PTK derivation failed");
+ return ret;
+ }
+
+#ifdef CONFIG_PASN
+ if (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
+ ret = wpa_ltf_keyseed(ptk, sm->key_mgmt, sm->pairwise_cipher);
+#endif /* CONFIG_PASN */
+
+ return ret;
}
@@ -257,6 +270,8 @@
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
#ifdef CONFIG_FILS
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
@@ -467,6 +482,7 @@
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
+ sm->tk_set = true;
wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
@@ -685,6 +701,15 @@
kdk_len) < 0)
return -1;
+#ifdef CONFIG_PASN
+ if (sm->secure_ltf &&
+ ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) &&
+ wpa_ltf_keyseed(&sm->ptk, sm->key_mgmt, sm->pairwise_cipher)) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to derive LTF keyseed");
+ return -1;
+ }
+#endif /* CONFIG_PASN */
+
if (wpa_key_mgmt_fils(sm->key_mgmt)) {
kck = sm->ptk.kck2;
kck_len = sm->ptk.kck2_len;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 579616f..3811c3b 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -27,6 +27,7 @@
size_t pmk_len;
struct wpa_ptk ptk, tptk;
int ptk_set, tptk_set;
+ bool tk_set; /* Whether any TK is configured to the driver */
unsigned int msg_3_of_4_ok:1;
u8 snonce[WPA_NONCE_LEN];
u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
@@ -482,6 +483,18 @@
ptk);
}
+#ifdef CONFIG_PASN
+static inline int wpa_sm_set_ltf_keyseed(struct wpa_sm *sm, const u8 *own_addr,
+ const u8 *peer_addr,
+ size_t ltf_keyseed_len,
+ const u8 *ltf_keyseed)
+{
+ WPA_ASSERT(sm->ctx->set_ltf_keyseed);
+ return sm->ctx->set_ltf_keyseed(sm->ctx->ctx, own_addr, peer_addr,
+ ltf_keyseed_len, ltf_keyseed);
+}
+#endif /* CONFIG_PASN */
+
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 3ba722f..c4e660f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -191,8 +191,12 @@
#ifdef CONFIG_SAE
} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ } else if (key_mgmt == WPA_KEY_MGMT_SAE_EXT_KEY) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+ } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
#endif /* CONFIG_SAE */
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
diff --git a/src/utils/crc32.c b/src/utils/crc32.c
index 12d9e2a..3712549 100644
--- a/src/utils/crc32.c
+++ b/src/utils/crc32.c
@@ -72,7 +72,7 @@
};
-u32 crc32(const u8 *frame, size_t frame_len)
+u32 ieee80211_crc32(const u8 *frame, size_t frame_len)
{
size_t i;
u32 crc;
diff --git a/src/utils/crc32.h b/src/utils/crc32.h
index dc31399..71a19dc 100644
--- a/src/utils/crc32.h
+++ b/src/utils/crc32.h
@@ -9,6 +9,6 @@
#ifndef CRC32_H
#define CRC32_H
-u32 crc32(const u8 *frame, size_t frame_len);
+u32 ieee80211_crc32(const u8 *frame, size_t frame_len);
#endif /* CRC32_H */
diff --git a/src/utils/ip_addr.c b/src/utils/ip_addr.c
index 92a3590..a971f72 100644
--- a/src/utils/ip_addr.c
+++ b/src/utils/ip_addr.c
@@ -51,3 +51,22 @@
return -1;
}
+
+
+bool hostapd_ip_equal(const struct hostapd_ip_addr *a,
+ const struct hostapd_ip_addr *b)
+{
+ if (a->af != b->af)
+ return false;
+
+ if (a->af == AF_INET && a->u.v4.s_addr == b->u.v4.s_addr)
+ return true;
+
+#ifdef CONFIG_IPV6
+ if (a->af == AF_INET6 &&
+ os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) == 0)
+ return true;
+#endif /* CONFIG_IPV6 */
+
+ return false;
+}
diff --git a/src/utils/ip_addr.h b/src/utils/ip_addr.h
index 0670411..1d35e0b 100644
--- a/src/utils/ip_addr.h
+++ b/src/utils/ip_addr.h
@@ -23,5 +23,7 @@
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
size_t buflen);
int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
+bool hostapd_ip_equal(const struct hostapd_ip_addr *a,
+ const struct hostapd_ip_addr *b);
#endif /* IP_ADDR_H */
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index a338a20..9875b0e 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -621,12 +621,17 @@
#ifndef CONFIG_NO_WPA_MSG
static wpa_msg_cb_func wpa_msg_cb = NULL;
+static wpa_msg_cb_func wpa_msg_aidl_cb = NULL;
void wpa_msg_register_cb(wpa_msg_cb_func func)
{
wpa_msg_cb = func;
}
+void wpa_msg_register_aidl_cb(wpa_msg_cb_func func)
+{
+ wpa_msg_aidl_cb = func;
+}
static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
@@ -670,6 +675,8 @@
wpa_printf(level, "%s%s", prefix, buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
+ if (wpa_msg_aidl_cb)
+ wpa_msg_aidl_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
bin_clear_free(buf, buflen);
}
@@ -681,7 +688,7 @@
int buflen;
int len;
- if (!wpa_msg_cb)
+ if (!wpa_msg_cb && !wpa_msg_aidl_cb)
return;
va_start(ap, fmt);
@@ -697,7 +704,10 @@
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
- wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
+ if (wpa_msg_aidl_cb)
+ wpa_msg_aidl_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
bin_clear_free(buf, buflen);
}
@@ -725,6 +735,8 @@
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
+ if (wpa_msg_aidl_cb)
+ wpa_msg_aidl_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
bin_clear_free(buf, buflen);
}
@@ -736,7 +748,7 @@
int buflen;
int len;
- if (!wpa_msg_cb)
+ if (!wpa_msg_cb && !wpa_msg_aidl_cb)
return;
va_start(ap, fmt);
@@ -752,7 +764,10 @@
va_start(ap, fmt);
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
- wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
+ if (wpa_msg_aidl_cb)
+ wpa_msg_aidl_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
bin_clear_free(buf, buflen);
}
@@ -780,6 +795,9 @@
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
+ if (wpa_msg_aidl_cb)
+ wpa_msg_aidl_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
+
bin_clear_free(buf, buflen);
}
@@ -807,6 +825,8 @@
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len);
+ if (wpa_msg_aidl_cb)
+ wpa_msg_aidl_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len);
os_free(buf);
}
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index c6d5cc6..29fc48a 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -167,6 +167,7 @@
#define wpa_msg_no_global(args...) do { } while (0)
#define wpa_msg_global_only(args...) do { } while (0)
#define wpa_msg_register_cb(f) do { } while (0)
+#define wpa_msg_register_aidl_cb(f) do { } while (0)
#define wpa_msg_register_ifname_cb(f) do { } while (0)
#else /* CONFIG_NO_WPA_MSG */
/**
@@ -274,7 +275,7 @@
* @func: Callback function (%NULL to unregister)
*/
void wpa_msg_register_cb(wpa_msg_cb_func func);
-
+void wpa_msg_register_aidl_cb(wpa_msg_cb_func func);
typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 25b5b31..05c79c0 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -67,7 +67,7 @@
defaults: ["wpa_supplicant_cflags_defaults"],
srcs: [":wpa_supplicant_srcs"],
shared_libs: [
- "android.hardware.wifi.supplicant-V1-ndk",
+ "android.hardware.wifi.supplicant-V2-ndk",
"libbase",
"libbinder_ndk",
"libc",
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index d1436e2..1da9e61 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -276,6 +276,7 @@
OBJS += src/common/sae.c
ifdef CONFIG_SAE_PK
L_CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
OBJS += src/common/sae_pk.c
endif
NEED_ECC=y
@@ -1811,7 +1812,7 @@
LOCAL_SHARED_LIBRARIES += libdbus
endif
ifeq ($(WPA_SUPPLICANT_USE_AIDL), y)
-LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V1-ndk
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V2-ndk
LOCAL_SHARED_LIBRARIES += libutils libbase
LOCAL_SHARED_LIBRARIES += libbinder_ndk
LOCAL_STATIC_LIBRARIES += libwpa_aidl
@@ -1883,7 +1884,7 @@
aidl/sta_network.cpp \
aidl/supplicant.cpp
LOCAL_SHARED_LIBRARIES := \
- android.hardware.wifi.supplicant-V1-ndk \
+ android.hardware.wifi.supplicant-V2-ndk \
libbinder_ndk \
libbase \
libutils \
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 1c6911b..0a71558 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -266,6 +266,7 @@
OBJS += ../src/common/sae.o
ifdef CONFIG_SAE_PK
CFLAGS += -DCONFIG_SAE_PK
+NEED_AES_SIV=y
OBJS += ../src/common/sae_pk.o
endif
NEED_ECC=y
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index a099a85..0cc5f39 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -168,11 +168,16 @@
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
-# imsi_privacy_key: IMSI privacy key (PEM encoded X.509v3 certificate)
+# imsi_privacy_cert: IMSI privacy certificate (PEM encoded X.509v3 certificate)
# This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
# identity (IMSI) to improve privacy. The X.509v3 certificate needs to
# include a 2048-bit RSA public key and this is from the operator who
# authenticates the SIM/USIM.
+# imsi_privacy_attr: IMSI privacy attribute
+# This field is used to help the EAP-SIM/AKA/AKA' server to identify
+# the used certificate (and as such, the matching private key). This
+# is set to an attribute in name=value format if the operator needs
+# this information.
#
# domain_suffix_match: Constraint for server domain name
# If set, this FQDN is used as a suffix match requirement for the AAA
diff --git a/wpa_supplicant/aidl/Android.bp b/wpa_supplicant/aidl/Android.bp
index 0785fe1..24c2079 100644
--- a/wpa_supplicant/aidl/Android.bp
+++ b/wpa_supplicant/aidl/Android.bp
@@ -33,7 +33,7 @@
defaults: ["wpa_supplicant_cflags_defaults"],
soc_specific: true,
shared_libs: [
- "android.hardware.wifi.supplicant-V1-ndk",
+ "android.hardware.wifi.supplicant-V2-ndk",
"libbinder_ndk",
"libbase",
"libutils",
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index da90c38..33ad650 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -39,6 +39,7 @@
const std::vector<uint8_t> kZeroBssid = {0, 0, 0, 0, 0, 0};
using aidl::android::hardware::wifi::supplicant::GsmRand;
+using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
/**
* Check if the provided |wpa_supplicant| structure represents a P2P iface or
@@ -400,6 +401,7 @@
{
// Create the main aidl service object and register it.
wpa_printf(MSG_INFO, "Starting AIDL supplicant");
+ wpa_printf(MSG_INFO, "Interface version: %d", Supplicant::version);
supplicant_object_ = ndk::SharedRefBase::make<Supplicant>(global);
wpa_global_ = global;
std::string instance = std::string() + Supplicant::descriptor + "/default";
@@ -661,6 +663,8 @@
aidl_ssid.assign(
wpa_s->current_ssid->ssid,
wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+ wpa_printf(MSG_INFO, "assoc key_mgmt 0x%x network key_mgmt 0x%x",
+ wpa_s->key_mgmt, wpa_s->current_ssid->key_mgmt);
}
std::vector<uint8_t> bssid;
// wpa_supplicant sets the |pending_bssid| field when it starts a
@@ -680,12 +684,12 @@
std::function<
ndk::ScopedAStatus(std::shared_ptr<ISupplicantStaIfaceCallback>)>
func = std::bind(
- &ISupplicantStaIfaceCallback::onStateChanged,
+ &ISupplicantStaIfaceCallback::onStateChangedWithAkm,
std::placeholders::_1,
static_cast<StaIfaceCallbackState>(
wpa_s->wpa_state),
bssid, aidl_network_id, aidl_ssid,
- fils_hlp_sent);
+ fils_hlp_sent, (KeyMgmtMask) wpa_s->key_mgmt);
callWithEachStaIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname), func);
return 0;
@@ -1349,14 +1353,22 @@
dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
}
+ P2pGroupStartedEventParams params;
+ params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname);
+ params.isGroupOwner = aidl_is_go;
+ params.ssid = byteArrToVec(ssid->ssid, ssid->ssid_len);
+ params.frequencyMHz = aidl_freq;
+ params.psk = aidl_psk;
+ params.passphrase = misc_utils::charBufToString(ssid->passphrase);
+ params.isPersistent = aidl_is_persistent;
+ params.goDeviceAddress = macAddrToVec(wpa_group_s->go_dev_addr);
+ params.goInterfaceAddress = aidl_is_go ? macAddrToVec(wpa_group_s->own_addr) :
+ macAddrToVec(wpa_group_s->current_bss->bssid);
+
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
- std::bind(
- &ISupplicantP2pIfaceCallback::onGroupStarted,
- std::placeholders::_1, misc_utils::charBufToString(wpa_group_s->ifname),
- aidl_is_go, byteArrToVec(ssid->ssid, ssid->ssid_len),
- aidl_freq, aidl_psk, misc_utils::charBufToString(ssid->passphrase),
- macAddrToVec(wpa_group_s->go_dev_addr), aidl_is_persistent));
+ std::bind(&ISupplicantP2pIfaceCallback::onGroupStartedWithParams,
+ std::placeholders::_1, params));
}
void AidlManager::notifyP2pGroupRemoved(
diff --git a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml b/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
index 3dc9b02..b80dadd 100644
--- a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
+++ b/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
@@ -1,6 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.wifi.supplicant</name>
+ <version>2</version>
<fqname>ISupplicant/default</fqname>
</hal>
</manifest>
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/p2p_iface.cpp
index 06c4545..b19895b 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/p2p_iface.cpp
@@ -338,9 +338,7 @@
void joinScanWrapper(void *eloop_ctx, void *timeout_ctx)
{
- struct wpa_supplicant *wpa_s = (struct wpa_supplicant *) eloop_ctx;
-
- if (pending_join_scan_callback != NULL) {
+ if (pending_join_scan_callback) {
pending_join_scan_callback();
}
}
@@ -470,7 +468,7 @@
if (wpas_p2p_group_add_persistent(
wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
- CHANWIDTH_USE_HT, he, 0, NULL, 0, 0, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, he, 0, NULL, 0, 0, is6GhzAllowed(wpa_s))) {
ret = -1;
}
@@ -1289,6 +1287,9 @@
if (go_intent > 15) {
return {"", createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
}
+ if (peer_address.size() != ETH_ALEN) {
+ return {"", createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
+ }
int go_intent_signed = join_existing_group ? -1 : go_intent;
p2p_wps_method wps_method = {};
switch (provision_method) {
@@ -1305,13 +1306,14 @@
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int edmg = wpa_s->conf->p2p_go_edmg;
const char* pin =
pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
bool auto_join = !join_existing_group;
int new_pin = wpas_p2p_connect(
wpa_s, peer_address.data(), pin, wps_method, persistent, auto_join,
join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
- vht, CHANWIDTH_USE_HT, he, 0, nullptr, 0, is6GhzAllowed(wpa_s));
+ vht, CONF_OPER_CHWIDTH_USE_HT, he, edmg, nullptr, 0, is6GhzAllowed(wpa_s));
if (new_pin < 0) {
return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
@@ -1370,7 +1372,6 @@
if (!wpa_group_s) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
}
- wpa_group_s->global->p2p_go_found_external_scan = 0;
if (wpas_p2p_group_remove(wpa_group_s, group_ifname.c_str())) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
@@ -1384,6 +1385,9 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
}
+ if (peer_address.size() != ETH_ALEN) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
if (wpas_p2p_reject(wpa_s, peer_address.data())) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
@@ -1396,6 +1400,9 @@
const std::vector<uint8_t>& peer_address)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (peer_address.size() != ETH_ALEN) {
+ return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+ }
if (wpas_p2p_invite_group(
wpa_s, group_ifname.c_str(), peer_address.data(),
go_device_address.data(), is6GhzAllowed(wpa_s))) {
@@ -1412,14 +1419,18 @@
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int edmg = wpa_s->conf->p2p_go_edmg;
struct wpa_ssid* ssid =
wpa_config_get_network(wpa_s->conf, persistent_network_id);
if (ssid == NULL || ssid->disabled != 2) {
return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
}
+ if (peer_address.size() != ETH_ALEN) {
+ return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+ }
if (wpas_p2p_invite(
wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- CHANWIDTH_USE_HT, 0, he, 0, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, 0, he, edmg, is6GhzAllowed(wpa_s))) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
@@ -1580,6 +1591,9 @@
if (!query_buf) {
return {0, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
+ if (peer_address.size() != ETH_ALEN) {
+ return {0, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+ }
const uint8_t* dst_addr = is_zero_ether_addr(peer_address.data())
? nullptr
: peer_address.data();
@@ -1626,6 +1640,9 @@
if (!wpa_group_s) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
}
+ if (bssid.size() != ETH_ALEN) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
const uint8_t* bssid_addr =
is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
#ifdef CONFIG_AP
@@ -1674,6 +1691,9 @@
if (!wpa_group_s) {
return {"", createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN)};
}
+ if (bssid.size() != ETH_ALEN) {
+ return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+ }
const uint8_t* bssid_addr =
is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
int pin = wpas_wps_start_pin(
@@ -1706,6 +1726,9 @@
const std::vector<uint8_t>& type)
{
std::array<uint8_t, 8> type_arr;
+ if (type.size() != 8) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
std::copy_n(type.begin(), 8, type_arr.begin());
return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type_arr);
}
@@ -1856,12 +1879,13 @@
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int edmg = wpa_s->conf->p2p_go_edmg;
struct wpa_ssid* ssid =
wpa_config_get_network(wpa_s->conf, persistent_network_id);
if (ssid == NULL) {
if (wpas_p2p_group_add(
wpa_s, persistent, 0, 0, ht40, vht,
- CHANWIDTH_USE_HT, he, 0, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, he, edmg, is6GhzAllowed(wpa_s))) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
} else {
return ndk::ScopedAStatus::ok();
@@ -1869,7 +1893,7 @@
} else if (ssid->disabled == 2) {
if (wpas_p2p_group_add_persistent(
wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
- CHANWIDTH_USE_HT, he, 0, NULL, 0, 0, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, he, edmg, NULL, 0, 0, is6GhzAllowed(wpa_s))) {
return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
} else {
return ndk::ScopedAStatus::ok();
@@ -1887,6 +1911,7 @@
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int edmg = wpa_s->conf->p2p_go_edmg;
if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
@@ -1914,7 +1939,7 @@
if (wpas_p2p_group_add(
wpa_s, persistent, freq, 0, ht40, vht,
- CHANWIDTH_USE_HT, he, 0, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, he, edmg, is6GhzAllowed(wpa_s))) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
@@ -1966,10 +1991,8 @@
struct wpa_bss *bss = findBssBySsid(
wpa_s, peer_address.data(), ssid.data(), ssid.size());
if (bss) {
- wpa_s->global->p2p_go_found_external_scan = 1;
if (0 != joinGroup(wpa_s, bss->bssid, ssid, passphrase)) {
wpa_printf(MSG_ERROR, "P2P: Failed to join a group.");
- wpa_s->global->p2p_go_found_external_scan = 0;
}
// no need to notify group join failure here,
// it will be handled by wpas_p2p_group_add_persistent
@@ -2018,11 +2041,16 @@
if (enable) {
wpa_s->conf->p2p_device_random_mac_addr = 1;
wpa_s->conf->p2p_interface_random_mac_addr = 1;
+ int status = wpas_p2p_mac_setup(wpa_s);
// restore config if it failed to set up MAC address.
- if (wpas_p2p_mac_setup(wpa_s) < 0) {
+ if (status < 0) {
wpa_s->conf->p2p_device_random_mac_addr = 0;
wpa_s->conf->p2p_interface_random_mac_addr = 0;
+ if (status == -ENOTSUP) {
+ return createStatusWithMsg(SupplicantStatusCode::FAILURE_UNSUPPORTED,
+ "Failed to set up MAC address, feature not supported.");
+ }
return createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
"Failed to set up MAC address.");
}
@@ -2093,6 +2121,9 @@
const std::vector<uint8_t>& peer_address, bool isLegacyClient)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (peer_address.size() != ETH_ALEN) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
wpas_p2p_remove_client(wpa_s, peer_address.data(), isLegacyClient? 1 : 0);
return ndk::ScopedAStatus::ok();
}
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index 7a07cc1..d88f6f0 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -50,6 +50,7 @@
WIDTH_80P80 = 4,
WIDTH_5 = 5,
WIDTH_10 = 6,
+ WIDTH_320 = 7,
WIDTH_INVALID = -1
};
@@ -1747,7 +1748,9 @@
if (wpa_s->connection_set) {
capa.legacyMode = LegacyMode::UNKNOWN;
- if (wpa_s->connection_he) {
+ if (wpa_s->connection_eht) {
+ capa.technology = WifiTechnology::EHT;
+ } else if (wpa_s->connection_he) {
capa.technology = WifiTechnology::HE;
} else if (wpa_s->connection_vht) {
capa.technology = WifiTechnology::VHT;
@@ -1778,6 +1781,9 @@
case CHAN_WIDTH_80P80:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
break;
+ case CHAN_WIDTH_320:
+ capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_320;
+ break;
default:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
break;
@@ -1817,6 +1823,12 @@
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TRUST_ON_FIRST_USE);
+ mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::SET_TLS_MINIMUM_VERSION);
+
+#ifdef EAP_TLSV1_3
+ mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TLS_V1_3);
+#endif
+
wpa_printf(MSG_DEBUG, "Driver capability mask: 0x%x", mask);
return {static_cast<WpaDriverCapabilitiesMask>(mask),
@@ -1930,7 +1942,23 @@
std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoInternal()
{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
MloLinksInfo linksInfo;
+ MloLink link;
+
+ if (!wpa_s->valid_links)
+ return {linksInfo, ndk::ScopedAStatus::ok()};
+
+ for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Add MLO Link ID %d info", i);
+ link.linkId = i;
+ link.staLinkMacAddress.assign(wpa_s->links[i].addr, wpa_s->links[i].addr + ETH_ALEN);
+ linksInfo.links.push_back(link);
+ }
+
return {linksInfo, ndk::ScopedAStatus::ok()};
}
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index 61c71a1..f9f980c 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -871,6 +871,14 @@
&StaNetwork::setRoamingConsortiumSelectionInternal, in_selectedRcoi);
}
+::ndk::ScopedAStatus StaNetwork::setMinimumTlsVersionEapPhase1Param(
+ TlsVersion in_tlsVersion)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setMinimumTlsVersionEapPhase1ParamInternal, in_tlsVersion);
+}
+
std::pair<uint32_t, ndk::ScopedAStatus> StaNetwork::getIdInternal()
{
return {network_id_, ndk::ScopedAStatus::ok()};
@@ -2005,10 +2013,13 @@
{
struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
int val = enable == true ? 1 : 0;
- std::string suiteb_phase1("tls_suiteb=" + std::to_string(val));
+ std::string phase1_params("tls_suiteb=" + std::to_string(val));
+ if (wpa_ssid->eap.phase1 != NULL) {
+ phase1_params.append(wpa_ssid->eap.phase1);
+ }
if (setStringKeyFieldAndResetState(
- suiteb_phase1.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
+ phase1_params.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
@@ -2597,6 +2608,41 @@
#endif
}
+ndk::ScopedAStatus StaNetwork::setMinimumTlsVersionEapPhase1ParamInternal(TlsVersion tlsVersion)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ std::string phase1_params;
+ if (wpa_ssid->eap.phase1 != NULL) {
+ phase1_params.append(wpa_ssid->eap.phase1);
+ }
+ if (tlsVersion < TlsVersion::TLS_V1_0) {
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+ // Fallback to disable lower version TLS cascadingly.
+ switch (tlsVersion) {
+ case TlsVersion::TLS_V1_3:
+ phase1_params.append("tls_disable_tlsv1_2=1");
+ FALLTHROUGH_INTENDED;
+ case TlsVersion::TLS_V1_2:
+ phase1_params.append("tls_disable_tlsv1_1=1");
+ FALLTHROUGH_INTENDED;
+ case TlsVersion::TLS_V1_1:
+ phase1_params.append("tls_disable_tlsv1_0=1");
+ FALLTHROUGH_INTENDED;
+ case TlsVersion::TLS_V1_0:
+ FALLTHROUGH_INTENDED;
+ default:
+ // no restriction
+ break;
+ }
+
+ if (setStringKeyFieldAndResetState(
+ phase1_params.c_str(), &(wpa_ssid->eap.phase1), "phase1")) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/aidl/sta_network.h b/wpa_supplicant/aidl/sta_network.h
index 524f44a..6661130 100644
--- a/wpa_supplicant/aidl/sta_network.h
+++ b/wpa_supplicant/aidl/sta_network.h
@@ -22,6 +22,7 @@
#include <aidl/android/hardware/wifi/supplicant/NetworkResponseEapSimUmtsAuthParams.h>
#include <aidl/android/hardware/wifi/supplicant/SaeH2eMode.h>
#include <aidl/android/hardware/wifi/supplicant/DppConnectionKeys.h>
+#include <aidl/android/hardware/wifi/supplicant/TlsVersion.h>
extern "C"
{
@@ -173,6 +174,8 @@
::ndk::ScopedAStatus enableSaePkOnlyMode(bool in_enable) override;
::ndk::ScopedAStatus setRoamingConsortiumSelection(
const std::vector<uint8_t>& in_selectedRcoi) override;
+ ::ndk::ScopedAStatus setMinimumTlsVersionEapPhase1Param(
+ TlsVersion in_tlsVersion) override;
private:
// Corresponding worker functions for the AIDL methods.
@@ -302,6 +305,7 @@
ndk::ScopedAStatus enableSaePkOnlyModeInternal(bool enable);
ndk::ScopedAStatus setRoamingConsortiumSelectionInternal(
const std::vector<uint8_t>& selectedRcoi);
+ ndk::ScopedAStatus setMinimumTlsVersionEapPhase1ParamInternal(TlsVersion tlsVersion);
struct wpa_ssid* retrieveNetworkPtr();
struct wpa_supplicant* retrieveIfacePtr();
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 52e4c04..bfdd53e 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -80,6 +80,7 @@
# EAP-TLS
CONFIG_EAP_TLS=y
+CONFIG_EAP_TLSV1_3=y
# EAL-PEAP
CONFIG_EAP_PEAP=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 94f0f83..16d6c90 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -90,7 +90,7 @@
&conf->op_class,
&conf->channel);
- if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
+ if (hostapd_get_oper_chwidth(conf) == CONF_OPER_CHWIDTH_80P80MHZ) {
ieee80211_freq_to_chan(ssid->vht_center_freq2,
&freq_seg_idx);
hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx);
@@ -112,15 +112,15 @@
#ifdef CONFIG_P2P
switch (hostapd_get_oper_chwidth(conf)) {
- case CHANWIDTH_80MHZ:
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel,
conf->op_class);
wpa_printf(MSG_DEBUG,
"VHT center channel %u for 80 or 80+80 MHz bandwidth",
center_chan);
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel,
conf->op_class);
wpa_printf(MSG_DEBUG,
@@ -133,7 +133,7 @@
* try oper_cwidth 160 MHz first then VHT 80 MHz, if 160 MHz is
* not supported.
*/
- hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ);
+ hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ);
ieee80211_freq_to_channel_ext(ssid->frequency, 0,
conf->vht_oper_chwidth,
&conf->op_class,
@@ -145,7 +145,7 @@
"VHT center channel %u for auto-selected 160 MHz bandwidth",
center_chan);
} else {
- hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ);
+ hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_80MHZ);
ieee80211_freq_to_channel_ext(ssid->frequency, 0,
conf->vht_oper_chwidth,
&conf->op_class,
@@ -174,11 +174,10 @@
conf->channel);
hostapd_set_oper_centr_freq_seg0_idx(
conf, conf->channel + conf->secondary_channel * 2);
- hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+ hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT);
ieee80211_freq_to_channel_ext(ssid->frequency, 0,
- conf->vht_oper_chwidth,
- &conf->op_class,
- &conf->channel);
+ conf->vht_oper_chwidth,
+ &conf->op_class, &conf->channel);
}
@@ -205,14 +204,14 @@
static int get_max_oper_chwidth_6ghz(int chwidth)
{
switch (chwidth) {
- case CHANWIDTH_USE_HT:
+ case CONF_OPER_CHWIDTH_USE_HT:
return 20;
- case CHANWIDTH_40MHZ_6GHZ:
+ case CONF_OPER_CHWIDTH_40MHZ_6GHZ:
return 40;
- case CHANWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
return 80;
- case CHANWIDTH_80P80MHZ:
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
return 160;
default:
return 0;
@@ -253,8 +252,8 @@
wpa_printf(MSG_DEBUG,
"Secondary channel offset %d for P2P group",
conf->secondary_channel);
- if (ssid->max_oper_chwidth == CHANWIDTH_40MHZ_6GHZ)
- ssid->max_oper_chwidth = CHANWIDTH_USE_HT;
+ if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_40MHZ_6GHZ)
+ ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT;
}
if ((is_chanwidth_40_80 || is_chanwidth_160) && ssid->p2p_group &&
@@ -270,7 +269,7 @@
struct hostapd_config *conf)
{
conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0,
- CHANWIDTH_USE_HT,
+ CONF_OPER_CHWIDTH_USE_HT,
&conf->op_class,
&conf->channel);
if (conf->hw_mode == NUM_HOSTAPD_MODES) {
@@ -414,7 +413,9 @@
}
}
- if (conf->secondary_channel) {
+ if (wpa_s->p2p_go_no_pri_sec_switch) {
+ conf->no_pri_sec_switch = 1;
+ } else if (conf->secondary_channel) {
struct wpa_supplicant *iface;
for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
@@ -1238,9 +1239,11 @@
void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
- const u8 *src_addr, const u8 *buf, size_t len)
+ const u8 *src_addr, const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
- ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len);
+ ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len,
+ encrypted);
}
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index ccd3e7b..865429e 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -16,7 +16,8 @@
struct wpa_ssid *ssid);
void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
- const u8 *src_addr, const u8 *buf, size_t len);
+ const u8 *src_addr, const u8 *buf, size_t len,
+ enum frame_encryption encrypted);
int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *p2p_dev_addr);
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 429c6e7..a3da86c 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -379,6 +379,8 @@
static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
+ int i;
+
if (bss == wpa_s->current_bss)
return 1;
@@ -388,9 +390,23 @@
bss->ssid_len) != 0))
return 0; /* SSID has changed */
- return !is_zero_ether_addr(bss->bssid) &&
- (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
- os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0);
+ if (!is_zero_ether_addr(bss->bssid) &&
+ (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+ os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0))
+ return 1;
+
+ if (!wpa_s->valid_links)
+ return 0;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ if (os_memcmp(bss->bssid, wpa_s->links[i].bssid, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
}
@@ -441,7 +457,11 @@
struct os_reltime *fetch_time)
{
struct wpa_bss *bss;
- char extra[50];
+ char extra[100];
+ const u8 *ml_ie;
+ char *pos, *end;
+ int ret = 0;
+ const u8 *mld_addr;
bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
if (bss == NULL)
@@ -456,6 +476,14 @@
os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
wpa_bss_set_hessid(bss);
+ os_memset(bss->mld_addr, 0, ETH_ALEN);
+ ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
+ if (ml_ie) {
+ mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1);
+ if (mld_addr)
+ os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
+ }
+
if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
wpa_bss_remove_oldest(wpa_s) != 0) {
wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
@@ -467,11 +495,21 @@
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
wpa_s->num_bss++;
+
+ extra[0] = '\0';
+ pos = extra;
+ end = pos + sizeof(extra);
if (!is_zero_ether_addr(bss->hessid))
- os_snprintf(extra, sizeof(extra), " HESSID " MACSTR,
- MAC2STR(bss->hessid));
- else
- extra[0] = '\0';
+ ret = os_snprintf(pos, end - pos, " HESSID " MACSTR,
+ MAC2STR(bss->hessid));
+
+ if (!is_zero_ether_addr(bss->mld_addr) &&
+ !os_snprintf_error(end - pos, ret)) {
+ pos += ret;
+ ret = os_snprintf(pos, end - pos, " MLD ADDR " MACSTR,
+ MAC2STR(bss->mld_addr));
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
" SSID '%s' freq %d%s",
bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
@@ -708,8 +746,19 @@
}
dl_list_add(prev, &bss->list_id);
}
- if (changes & WPA_BSS_IES_CHANGED_FLAG)
+ if (changes & WPA_BSS_IES_CHANGED_FLAG) {
+ const u8 *ml_ie, *mld_addr;
+
wpa_bss_set_hessid(bss);
+ os_memset(bss->mld_addr, 0, ETH_ALEN);
+ ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
+ if (ml_ie) {
+ mld_addr = get_basic_mle_mld_addr(&ml_ie[3],
+ ml_ie[1] - 1);
+ if (mld_addr)
+ os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
+ }
+ }
dl_list_add_tail(&wpa_s->bss, &bss->list);
notify_bss_changes(wpa_s, changes, bss);
@@ -1281,12 +1330,16 @@
end = pos + bss->beacon_ie_len;
while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
+ u8 id, len;
+
+ id = *pos++;
+ len = *pos++;
+ if (len > end - pos)
break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
+ if (id == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
+ vendor_type == WPA_GET_BE32(pos))
+ wpabuf_put_data(buf, pos + 4, len - 4);
+ pos += len;
}
if (wpabuf_len(buf) == 0) {
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 146aaee..b68fc87 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -122,6 +122,8 @@
size_t ie_len;
/** Length of the following Beacon IE field in octets */
size_t beacon_ie_len;
+ /** MLD address of the AP */
+ u8 mld_addr[ETH_ALEN];
/* followed by ie_len octets of IEs */
/* followed by beacon_ie_len octets of IEs */
u8 ies[];
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c8844bb..065b6fb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -804,8 +804,12 @@
#ifdef CONFIG_SAE
else if (os_strcmp(start, "SAE") == 0)
val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "SAE-EXT-KEY") == 0)
+ val |= WPA_KEY_MGMT_SAE_EXT_KEY;
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
+ else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
else if (os_strcmp(start, "OSEN") == 0)
@@ -1004,6 +1008,16 @@
pos += ret;
}
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, "%sSAE-EXT-KEY",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+
if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
ret = os_snprintf(pos, end - pos, "%sFT-SAE",
pos == buf ? "" : " ");
@@ -1013,6 +1027,16 @@
}
pos += ret;
}
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, "%sFT-SAE-EXT-KEY",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_HS20
@@ -2434,8 +2458,8 @@
{ INT_RANGE(ht, 0, 1) },
{ INT_RANGE(vht, 0, 1) },
{ INT_RANGE(ht40, -1, 1) },
- { INT_RANGE(max_oper_chwidth, CHANWIDTH_USE_HT,
- CHANWIDTH_80P80MHZ) },
+ { INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT,
+ CONF_OPER_CHWIDTH_80P80MHZ) },
{ INT(vht_center_freq1) },
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
@@ -2503,7 +2527,8 @@
{ INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
{ INTe(sim_num, sim_num) },
- { STRe(imsi_privacy_key, imsi_privacy_key) },
+ { STRe(imsi_privacy_cert, imsi_privacy_cert) },
+ { STRe(imsi_privacy_attr, imsi_privacy_attr) },
{ STRe(openssl_ciphers, openssl_ciphers) },
{ INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
@@ -2629,6 +2654,7 @@
{ STR_LEN(dpp_csign) },
{ STR_LEN(dpp_pp_key) },
{ INT_RANGE(dpp_pfs, 0, 2) },
+ { INT_RANGE(dpp_connector_privacy, 0, 1) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
{ INT_RANGE(owe_only, 0, 1) },
@@ -2771,7 +2797,8 @@
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
- os_free(eap->imsi_privacy_key);
+ os_free(eap->imsi_privacy_cert);
+ os_free(eap->imsi_privacy_attr);
os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
bin_clear_free(eap->machine_password, eap->machine_password_len);
@@ -2875,7 +2902,8 @@
os_free(cred->req_conn_capab_port[i]);
os_free(cred->req_conn_capab_port);
os_free(cred->req_conn_capab_proto);
- os_free(cred->imsi_privacy_key);
+ os_free(cred->imsi_privacy_cert);
+ os_free(cred->imsi_privacy_attr);
os_free(cred);
}
@@ -2967,6 +2995,8 @@
#endif /* CONFIG_MBO */
os_free(config->dpp_name);
os_free(config->dpp_mud_url);
+ os_free(config->dpp_extra_conf_req_name);
+ os_free(config->dpp_extra_conf_req_value);
os_free(config);
}
@@ -3911,9 +3941,15 @@
return 0;
}
- if (os_strcmp(var, "imsi_privacy_key") == 0) {
- os_free(cred->imsi_privacy_key);
- cred->imsi_privacy_key = val;
+ if (os_strcmp(var, "imsi_privacy_cert") == 0) {
+ os_free(cred->imsi_privacy_cert);
+ cred->imsi_privacy_cert = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "imsi_privacy_attr") == 0) {
+ os_free(cred->imsi_privacy_attr);
+ cred->imsi_privacy_attr = val;
return 0;
}
@@ -4067,8 +4103,11 @@
if (os_strcmp(var, "imsi") == 0)
return alloc_strdup(cred->imsi);
- if (os_strcmp(var, "imsi_privacy_key") == 0)
- return alloc_strdup(cred->imsi_privacy_key);
+ if (os_strcmp(var, "imsi_privacy_cert") == 0)
+ return alloc_strdup(cred->imsi_privacy_cert);
+
+ if (os_strcmp(var, "imsi_privacy_attr") == 0)
+ return alloc_strdup(cred->imsi_privacy_attr);
if (os_strcmp(var, "milenage") == 0) {
if (!(cred->milenage))
@@ -5290,6 +5329,9 @@
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
{ STR(dpp_name), 0 },
{ STR(dpp_mud_url), 0 },
+ { STR(dpp_extra_conf_req_name), 0 },
+ { STR(dpp_extra_conf_req_value), 0 },
+ { INT_RANGE(dpp_connector_privacy_default, 0, 1), 0 },
#endif /* CONFIG_DPP */
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
{ INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 77d6ab5..a81e9eb 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -182,14 +182,24 @@
char *milenage;
/**
- * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+ * imsi_privacy_cert - IMSI privacy certificate
*
* This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
- * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
- * include a 2048-bit RSA public key and this is from the operator who
- * authenticates the SIM/USIM.
+ * identity (IMSI) to improve privacy. The referenced PEM-encoded
+ * X.509v3 certificate needs to include a 2048-bit RSA public key and
+ * this is from the operator who authenticates the SIM/USIM.
*/
- char *imsi_privacy_key;
+ char *imsi_privacy_cert;
+
+ /**
+ * imsi_privacy_attr - IMSI privacy attribute
+ *
+ * This field is used to help the EAP-SIM/AKA/AKA' server to identify
+ * the used certificate (and as such, the matching private key). This
+ * is set to an attribute in name=value format if the operator needs
+ * this information.
+ */
+ char *imsi_privacy_attr;
/**
* engine - Use an engine for private key operations
@@ -1617,6 +1627,25 @@
char *dpp_mud_url;
/**
+ * dpp_extra_conf_req_name - JSON node name of additional data for
+ * Enrollee's DPP Configuration Request
+ */
+ char *dpp_extra_conf_req_name;
+
+ /**
+ * dpp_extra_conf_req_value - JSON node data of additional data for
+ * Enrollee's DPP Configuration Request
+ */
+ char *dpp_extra_conf_req_value;
+
+ /* dpp_connector_privacy_default - Default valur for Connector privacy
+ *
+ * This value is used as the default for the dpp_connector_privacy
+ * network parameter for all new networks provisioned using DPP.
+ */
+ int dpp_connector_privacy_default;
+
+ /**
* coloc_intf_reporting - Colocated interference reporting
*
* dot11CoLocIntfReportingActivated
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 978cc6a..260df8f 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -833,6 +833,7 @@
STR(dpp_csign);
STR(dpp_pp_key);
INT(dpp_pfs);
+ INT(dpp_connector_privacy);
#endif /* CONFIG_DPP */
INT(owe_group);
INT(owe_only);
@@ -1036,6 +1037,13 @@
fprintf(f, "\tcert_id=\"%s\"\n", cred->cert_id);
if (cred->ca_cert_id)
fprintf(f, "\tca_cert_id=\"%s\"\n", cred->ca_cert_id);
+
+ if (cred->imsi_privacy_cert)
+ fprintf(f, "\timsi_privacy_cert=\"%s\"\n",
+ cred->imsi_privacy_cert);
+ if (cred->imsi_privacy_attr)
+ fprintf(f, "\timsi_privacy_attr=\"%s\"\n",
+ cred->imsi_privacy_attr);
}
@@ -1536,6 +1544,19 @@
if (config->dpp_config_processing)
fprintf(f, "dpp_config_processing=%d\n",
config->dpp_config_processing);
+ if (config->dpp_name)
+ fprintf(f, "dpp_name=%s\n", config->dpp_name);
+ if (config->dpp_mud_url)
+ fprintf(f, "dpp_mud_url=%s\n", config->dpp_mud_url);
+ if (config->dpp_extra_conf_req_name)
+ fprintf(f, "dpp_extra_conf_req_name=%s\n",
+ config->dpp_extra_conf_req_name);
+ if (config->dpp_extra_conf_req_value)
+ fprintf(f, "dpp_extra_conf_req_value=%s\n",
+ config->dpp_extra_conf_req_value);
+ if (config->dpp_connector_privacy_default)
+ fprintf(f, "dpp_connector_privacy_default=%d\n",
+ config->dpp_connector_privacy_default);
if (config->coloc_intf_reporting)
fprintf(f, "coloc_intf_reporting=%d\n",
config->coloc_intf_reporting);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 4d3d114..adc1a06 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -560,7 +560,7 @@
int he;
- int max_oper_chwidth;
+ enum oper_chan_width max_oper_chwidth;
unsigned int vht_center_freq1;
unsigned int vht_center_freq2;
@@ -1064,6 +1064,14 @@
int dpp_pfs_fallback;
/**
+ * dpp_connector_privacy - Network introduction type
+ * 0: unprotected variant from DPP R1
+ * 1: privacy protecting (station Connector encrypted) variant from
+ * DPP R3
+ */
+ int dpp_connector_privacy;
+
+ /**
* owe_group - OWE DH Group
*
* 0 = use default (19) first and then try all supported groups one by
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e8a8118..7118cab 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -866,6 +866,8 @@
} else if (os_strcasecmp(cmd,
"dpp_ignore_netaccesskey_mismatch") == 0) {
wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value);
+ } else if (os_strcasecmp(cmd, "dpp_discard_public_action") == 0) {
+ wpa_s->dpp_discard_public_action = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
dpp_test = atoi(value);
#endif /* CONFIG_DPP */
@@ -2383,6 +2385,14 @@
return pos - buf;
pos += ret;
+ if (wpa_s->valid_links) {
+ ret = os_snprintf(pos, end - pos, "ap_mld_addr=" MACSTR "\n",
+ MAC2STR(wpa_s->ap_mld_addr));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
#ifdef CONFIG_HS20
if (wpa_s->current_bss &&
(hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss,
@@ -2537,12 +2547,21 @@
wpa_s->current_ssid->ssid_len) : "");
if (wpa_s->wpa_state == WPA_COMPLETED) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ char mld_addr[50];
+
+ mld_addr[0] = '\0';
+ if (wpa_s->valid_links)
+ os_snprintf(mld_addr, sizeof(mld_addr),
+ " ap_mld_addr=" MACSTR,
+ MAC2STR(wpa_s->ap_mld_addr));
+
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED
"- connection to " MACSTR
- " completed %s [id=%d id_str=%s]",
+ " completed %s [id=%d id_str=%s]%s",
MAC2STR(wpa_s->bssid), "(auth)",
ssid ? ssid->id : -1,
- ssid && ssid->id_str ? ssid->id_str : "");
+ ssid && ssid->id_str ? ssid->id_str : "",
+ mld_addr);
}
}
#endif /* ANDROID */
@@ -2816,6 +2835,13 @@
return pos;
pos += ret;
}
+ if (data.key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, "%sSAE-EXT-KEY",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
#ifdef CONFIG_IEEE80211R
if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sFT/EAP",
@@ -2838,6 +2864,13 @@
return pos;
pos += ret;
}
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, "%sFT/SAE-EXT-KEY",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
#endif /* CONFIG_IEEE80211R */
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
@@ -3236,7 +3269,8 @@
return -1;
}
if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
- ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
+ ssid->key_mgmt != WPA_KEY_MGMT_SAE &&
+ ssid->key_mgmt != WPA_KEY_MGMT_SAE_EXT_KEY) {
wpa_printf(MSG_ERROR,
"CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
return -1;
@@ -4318,6 +4352,12 @@
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, " FT-SAE-EXT-KEY");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_SHA384
if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384) {
@@ -4335,6 +4375,12 @@
return pos - buf;
pos += ret;
}
+ if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY) {
+ ret = os_snprintf(pos, end - pos, " SAE-EXT-KEY");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_SHA256
if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256) {
@@ -5397,6 +5443,15 @@
}
#endif /* CONFIG_FILS */
+ if (!is_zero_ether_addr(bss->mld_addr)) {
+ ret = os_snprintf(pos, end - pos,
+ "ap_mld_addr=" MACSTR "\n",
+ MAC2STR(bss->mld_addr));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
if (mask & WPA_BSS_MASK_DELIM) {
ret = os_snprintf(pos, end - pos, "====\n");
if (os_snprintf_error(end - pos, ret))
@@ -5978,17 +6033,19 @@
if (freq2 < 0)
return -1;
if (freq2)
- return CHANWIDTH_80P80MHZ;
+ return CONF_OPER_CHWIDTH_80P80MHZ;
switch (chwidth) {
case 0:
case 20:
case 40:
- return CHANWIDTH_USE_HT;
+ return CONF_OPER_CHWIDTH_USE_HT;
case 80:
- return CHANWIDTH_80MHZ;
+ return CONF_OPER_CHWIDTH_80MHZ;
case 160:
- return CHANWIDTH_160MHZ;
+ return CONF_OPER_CHWIDTH_160MHZ;
+ case 320:
+ return CONF_OPER_CHWIDTH_320MHZ;
default:
wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d",
chwidth);
@@ -6095,7 +6152,7 @@
return -1;
if (allow_6ghz && chwidth == 40)
- max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+ max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
pos2 = os_strstr(pos, " ssid=");
if (pos2) {
@@ -6751,7 +6808,7 @@
allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL;
if (allow_6ghz && chwidth == 40)
- max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+ max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
max_oper_chwidth, pref_freq, he, edmg,
@@ -6897,7 +6954,7 @@
return -1;
if (allow_6ghz && chwidth == 40)
- max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+ max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
/* Allow DFS to be used for Autonomous GO */
wpa_s->p2p_go_allow_dfs = !!(wpa_s->drv_flags &
@@ -8123,7 +8180,7 @@
int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
enum wpa_driver_if_type if_type,
unsigned int *num,
- unsigned int *freq_list)
+ struct weighted_pcl *freq_list)
{
char *pos = wpa_s->get_pref_freq_list_override;
char *end;
@@ -8147,7 +8204,8 @@
pos++;
end = os_strchr(pos, ' ');
while (pos && (!end || pos < end) && count < *num) {
- freq_list[count++] = atoi(pos);
+ freq_list[count].freq = atoi(pos);
+ freq_list[count++].flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI;
pos = os_strchr(pos, ',');
if (pos)
pos++;
@@ -8162,10 +8220,11 @@
static int wpas_ctrl_iface_get_pref_freq_list(
struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
{
- unsigned int freq_list[100], num = 100, i;
+ unsigned int num = 100, i;
int ret;
enum wpa_driver_if_type iface_type;
char *pos, *end;
+ struct weighted_pcl freq_list[100];
pos = buf;
end = buf + buflen;
@@ -8196,7 +8255,7 @@
for (i = 0; i < num; i++) {
ret = os_snprintf(pos, end - pos, "%s%u",
- i > 0 ? "," : "", freq_list[i]);
+ i > 0 ? "," : "", freq_list[i].freq);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -8437,6 +8496,19 @@
wpas_dpp_chirp_stop(wpa_s);
wpa_s->dpp_pfs_fallback = 0;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ {
+ int i;
+
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ struct dpp_pb_info *info;
+
+ info = &wpa_s->dpp_pb[i];
+ info->rx_time.sec = 0;
+ info->rx_time.usec = 0;
+ }
+ }
+#endif /* CONFIG_DPP3 */
#ifdef CONFIG_TESTING_OPTIONS
os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
@@ -8556,6 +8628,8 @@
wpa_s->dpp_discovery_override = NULL;
os_free(wpa_s->dpp_groups_override);
wpa_s->dpp_groups_override = NULL;
+ wpa_s->dpp_ignore_netaccesskey_mismatch = 0;
+ wpa_s->dpp_discard_public_action = 0;
dpp_test = DPP_TEST_DISABLED;
#endif /* CONFIG_DPP */
#endif /* CONFIG_TESTING_OPTIONS */
@@ -8840,6 +8914,7 @@
unsigned int manual_scan_only_new = 0;
unsigned int scan_only = 0;
unsigned int scan_id_count = 0;
+ unsigned int manual_non_coloc_6ghz = 0;
int scan_id[MAX_SCAN_ID];
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -8917,6 +8992,10 @@
os_strstr(params, "wildcard_ssid=1") != NULL;
}
+ pos = os_strstr(params, "non_coloc_6ghz=");
+ if (pos)
+ manual_non_coloc_6ghz = !!atoi(pos + 15);
+
pos = params;
while (pos && *pos != '\0') {
if (os_strncmp(pos, "ssid ", 5) == 0) {
@@ -8986,6 +9065,7 @@
wpa_s->manual_scan_use_id = manual_scan_use_id;
wpa_s->manual_scan_only_new = manual_scan_only_new;
wpa_s->scan_id_count = scan_id_count;
+ wpa_s->manual_non_coloc_6ghz = manual_non_coloc_6ghz;
os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
wpa_s->scan_res_handler = scan_res_handler;
os_free(wpa_s->manual_scan_freqs);
@@ -9009,6 +9089,7 @@
wpa_s->manual_scan_use_id = manual_scan_use_id;
wpa_s->manual_scan_only_new = manual_scan_only_new;
wpa_s->scan_id_count = scan_id_count;
+ wpa_s->manual_non_coloc_6ghz = manual_non_coloc_6ghz;
os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
wpa_s->scan_res_handler = scan_res_handler;
os_free(wpa_s->manual_scan_freqs);
@@ -9523,7 +9604,7 @@
return -1;
}
- wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
+ wpa_supplicant_rx_eapol(wpa_s, src, buf, len, FRAME_ENCRYPTION_UNKNOWN);
os_free(buf);
return 0;
@@ -10022,8 +10103,9 @@
setup_cmd = atoi(tok_s + os_strlen(" setup_cmd="));
tok_s = os_strstr(cmd, " twt=");
- if (tok_s)
- sscanf(tok_s + os_strlen(" twt="), "%llu", &twt);
+ if (tok_s &&
+ sscanf(tok_s + os_strlen(" twt="), "%llu", &twt) != 1)
+ return -1;
tok_s = os_strstr(cmd, " requestor=");
if (tok_s)
@@ -10816,6 +10898,8 @@
#ifdef CONFIG_SAE
} else if (os_strcmp(token, "akmp=SAE") == 0) {
akmp = WPA_KEY_MGMT_SAE;
+ } else if (os_strcmp(token, "akmp=SAE-EXT-KEY") == 0) {
+ akmp = WPA_KEY_MGMT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
} else if (os_strcmp(token, "akmp=FILS-SHA256") == 0) {
@@ -10858,8 +10942,8 @@
goto out;
}
- ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id,
- comeback, comeback_len);
+ ret = wpas_pasn_auth_start(wpa_s, wpa_s->own_addr, bssid, akmp, cipher,
+ group, id, comeback, comeback_len);
out:
os_free(comeback);
return ret;
@@ -10877,7 +10961,7 @@
return -1;
}
- return wpas_pasn_deauthenticate(wpa_s, bssid);
+ return wpas_pasn_deauthenticate(wpa_s, wpa_s->own_addr, bssid);
}
#endif /* CONFIG_PASN */
@@ -11458,6 +11542,117 @@
}
+static int wpas_ctrl_iface_mlo_signal_poll(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+ struct wpa_mlo_signal_info mlo_si;
+
+ if (!wpa_s->valid_links)
+ return -1;
+
+ ret = wpa_drv_mlo_signal_poll(wpa_s, &mlo_si);
+ if (ret)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo_si.valid_links & BIT(i)))
+ continue;
+
+ ret = os_snprintf(pos, end - pos,
+ "LINK_ID=%d\nRSSI=%d\nLINKSPEED=%d\n"
+ "NOISE=%d\nFREQUENCY=%u\n",
+ i, mlo_si.links[i].current_signal,
+ mlo_si.links[i].current_txrate / 1000,
+ mlo_si.links[i].current_noise,
+ mlo_si.links[i].frequency);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+
+ if (mlo_si.links[i].chanwidth != CHAN_WIDTH_UNKNOWN) {
+ ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
+ channel_width_to_string(
+ mlo_si.links[i].chanwidth));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].center_frq1 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n",
+ mlo_si.links[i].center_frq1);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].center_frq2 > 0) {
+ ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n",
+ mlo_si.links[i].center_frq2);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].avg_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_RSSI=%d\n",
+ mlo_si.links[i].avg_signal);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (mlo_si.links[i].avg_beacon_signal) {
+ ret = os_snprintf(pos, end - pos,
+ "AVG_BEACON_RSSI=%d\n",
+ mlo_si.links[i].avg_beacon_signal);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
+static int wpas_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ if (!wpa_s->valid_links)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ ret = os_snprintf(pos, end - pos, "link_id=%d\nfreq=%u\n"
+ "ap_link_addr=" MACSTR
+ "\nsta_link_addr=" MACSTR "\n",
+ i, wpa_s->links[i].freq,
+ MAC2STR(wpa_s->links[i].bssid),
+ MAC2STR(wpa_s->links[i].addr));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -12439,6 +12634,14 @@
if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0)
reply_len = -1;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) {
+ if (wpas_dpp_push_button(wpa_s, NULL) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DPP_PUSH_BUTTON ", 16) == 0) {
+ if (wpas_dpp_push_button(wpa_s, buf + 15) < 0)
+ reply_len = -1;
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
} else if (os_strncmp(buf, "MSCS ", 5) == 0) {
if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5))
@@ -12464,6 +12667,12 @@
} else if (os_strncmp(buf, "DSCP_QUERY ", 11) == 0) {
if (wpas_ctrl_iface_send_dscp_query(wpa_s, buf + 11))
reply_len = -1;
+ } else if (os_strcmp(buf, "MLO_STATUS") == 0) {
+ reply_len = wpas_ctrl_iface_mlo_status(wpa_s, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "MLO_SIGNAL_POLL") == 0) {
+ reply_len = wpas_ctrl_iface_mlo_signal_poll(wpa_s, reply,
+ reply_size);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 0b1002b..26f7738 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -908,8 +908,10 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
+ dbus_bool_t b = wpa_debug_timestamp ? TRUE : FALSE;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
- &wpa_debug_timestamp, error);
+ &b, error);
}
@@ -927,8 +929,10 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
+ dbus_bool_t b = wpa_debug_show_keys ? TRUE : FALSE;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
- &wpa_debug_show_keys, error);
+ &b, error);
}
@@ -3131,12 +3135,16 @@
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-eap") ||
- ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-eap")))
+ &iter_array, "wpa-eap"))
goto nomem;
+#ifdef CONFIG_IEEE80211R
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-eap"))
+ goto nomem;
+#endif /* CONFIG_IEEE80211R */
+
/* TODO: Ensure that driver actually supports sha256 encryption. */
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "wpa-eap-sha256"))
@@ -3146,12 +3154,16 @@
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-psk") ||
- ((capa.key_mgmt &
+ &iter_array, "wpa-psk"))
+ goto nomem;
+
+#ifdef CONFIG_IEEE80211R
+ if ((capa.key_mgmt &
WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-psk")))
+ &iter_array, "wpa-ft-psk"))
goto nomem;
+#endif /* CONFIG_IEEE80211R */
/* TODO: Ensure that driver actually supports sha256 encryption. */
if (!wpa_dbus_dict_string_array_add_element(
@@ -5095,7 +5107,7 @@
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[16]; /* max 16 key managements may be supported */
+ const char *key_mgmt[18]; /* max 18 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -5145,8 +5157,12 @@
#ifdef CONFIG_SAE
if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
key_mgmt[n++] = "sae";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
+ key_mgmt[n++] = "sae-ext-key";
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
key_mgmt[n++] = "ft-sae";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
+ key_mgmt[n++] = "ft-sae-ext-key";
#endif /* CONFIG_SAE */
#ifdef CONFIG_OWE
if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 02012d1..9a7d601 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -2,7 +2,7 @@
<refentry>
<refentryinfo>
- <date>07 August 2019</date>
+ <date>13 September 2022</date>
</refentryinfo>
<refmeta>
@@ -22,6 +22,7 @@
<arg>-D<replaceable>driver</replaceable></arg>
<arg>-P<replaceable>PID_file</replaceable></arg>
<arg>-f<replaceable>output file</replaceable></arg>
+ <arg>-I<replaceable>additional config file</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -341,6 +342,13 @@
</varlistentry>
<varlistentry>
+ <term>-I filename</term>
+ <listitem>
+ <para>Path to additional configuration file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-d</term>
<listitem>
<para>Increase debugging verbosity (<option>-dd</option> even
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index b6dbc98..55dcd70 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -17,6 +17,7 @@
#include "common/dpp.h"
#include "common/gas.h"
#include "common/gas_server.h"
+#include "crypto/random.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "wpa_supplicant_i.h"
@@ -802,7 +803,17 @@
}
addr = get_param(cmd, " tcp_addr=");
- if (addr) {
+ if (addr && os_strcmp(addr, "from-uri") == 0) {
+ os_free(addr);
+ if (!peer_bi->host) {
+ wpa_printf(MSG_INFO,
+ "DPP: TCP address not available in peer URI");
+ return -1;
+ }
+ tcp = 1;
+ os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr));
+ tcp_port = peer_bi->port;
+ } else if (addr) {
int res;
res = hostapd_parse_ip_addr(addr, &ipaddr);
@@ -897,6 +908,9 @@
if (tcp)
return dpp_tcp_init(wpa_s->dpp, auth, &ipaddr, tcp_port,
wpa_s->conf->dpp_name, DPP_NETROLE_STA,
+ wpa_s->conf->dpp_mud_url,
+ wpa_s->conf->dpp_extra_conf_req_name,
+ wpa_s->conf->dpp_extra_conf_req_value,
wpa_s, wpa_s, wpas_dpp_process_conf_obj,
wpas_dpp_tcp_msg_sent);
#endif /* CONFIG_DPP2 */
@@ -1142,6 +1156,21 @@
return;
}
+ if (own_bi->type == DPP_BOOTSTRAP_PKEX) {
+ if (!peer_bi || peer_bi->type != DPP_BOOTSTRAP_PKEX) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "No matching peer bootstrapping key found for PKEX - ignore message");
+ return;
+ }
+
+ if (os_memcmp(peer_bi->pubkey_hash, own_bi->peer_pubkey_hash,
+ SHA256_MAC_LEN) != 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
+ "Mismatching peer PKEX bootstrapping key - ignore message");
+ return;
+ }
+ }
+
if (wpa_s->dpp_auth) {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL
"Already in DPP authentication exchange - ignore new one");
@@ -1267,6 +1296,9 @@
ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
+
+ ssid->dpp_connector_privacy =
+ wpa_s->conf->dpp_connector_privacy_default;
}
if (conf->c_sign_key) {
@@ -1606,6 +1638,14 @@
conf->server_name);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ if (!wpa_s->dpp_pb_result_indicated) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "success");
+ wpa_s->dpp_pb_result_indicated = true;
+ }
+
+#endif /* CONFIG_DPP3 */
+
return wpas_dpp_process_config(wpa_s, auth, conf);
}
@@ -1832,7 +1872,9 @@
buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name,
wpa_s->dpp_netrole,
wpa_s->conf->dpp_mud_url,
- supp_op_classes);
+ supp_op_classes,
+ wpa_s->conf->dpp_extra_conf_req_name,
+ wpa_s->conf->dpp_extra_conf_req_value);
os_free(supp_op_classes);
if (!buf) {
wpa_printf(MSG_DEBUG,
@@ -2019,6 +2061,42 @@
}
+#ifdef CONFIG_DPP3
+
+static bool wpas_dpp_pb_active(struct wpa_supplicant *wpa_s)
+{
+ return (wpa_s->dpp_pb_time.sec || wpa_s->dpp_pb_time.usec) &&
+ wpa_s->dpp_pb_configurator;
+}
+
+
+static void wpas_dpp_remove_pb_hash(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ if (!wpa_s->dpp_pb_bi)
+ return;
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ struct dpp_pb_info *info = &wpa_s->dpp_pb[i];
+
+ if (info->rx_time.sec == 0 && info->rx_time.usec == 0)
+ continue;
+ if (os_memcmp(info->hash, wpa_s->dpp_pb_resp_hash,
+ SHA256_MAC_LEN) == 0) {
+ /* Allow a new push button session to be established
+ * immediately without the successfully completed
+ * session triggering session overlap. */
+ info->rx_time.sec = 0;
+ info->rx_time.usec = 0;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Removed PB hash from session overlap detection due to successfully completed provisioning");
+ }
+ }
+}
+
+#endif /* CONFIG_DPP3 */
+
+
static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
@@ -2059,7 +2137,8 @@
int freq;
wpa_msg(wpa_s, MSG_INFO,
- DPP_EVENT_CONF_SENT "wait_conn_status=1");
+ DPP_EVENT_CONF_SENT "wait_conn_status=1 conf_status=%d",
+ auth->conf_resp_status);
wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
wpas_notify_dpp_config_accepted(wpa_s);
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
@@ -2080,7 +2159,8 @@
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (status == DPP_STATUS_OK) {
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d",
+ auth->conf_resp_status);
wpas_notify_dpp_config_sent(wpa_s);
}
else {
@@ -2090,6 +2170,20 @@
dpp_auth_deinit(auth);
wpa_s->dpp_auth = NULL;
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
+#ifdef CONFIG_DPP3
+ if (!wpa_s->dpp_pb_result_indicated && wpas_dpp_pb_active(wpa_s)) {
+ if (status == DPP_STATUS_OK)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
+ "success");
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
+ "no-configuration-available");
+ wpa_s->dpp_pb_result_indicated = true;
+ if (status == DPP_STATUS_OK)
+ wpas_dpp_remove_pb_hash(wpa_s);
+ wpas_dpp_push_button_stop(wpa_s);
+ }
+#endif /* CONFIG_DPP3 */
}
@@ -2706,19 +2800,38 @@
}
+static void wpas_dpp_pkex_clear_code(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->dpp_pkex_code && !wpa_s->dpp_pkex_identifier)
+ return;
+
+ /* Delete PKEX code and identifier on successful completion of
+ * PKEX. We are not supposed to reuse these without being
+ * explicitly requested to perform PKEX again. */
+ wpa_printf(MSG_DEBUG, "DPP: Delete PKEX code/identifier");
+ os_free(wpa_s->dpp_pkex_code);
+ wpa_s->dpp_pkex_code = NULL;
+ os_free(wpa_s->dpp_pkex_identifier);
+ wpa_s->dpp_pkex_identifier = NULL;
+
+}
+
+
#ifdef CONFIG_DPP2
static int wpas_dpp_pkex_done(void *ctx, void *conn,
struct dpp_bootstrap_info *peer_bi)
{
struct wpa_supplicant *wpa_s = ctx;
- const char *cmd = wpa_s->dpp_pkex_auth_cmd;
+ char cmd[500];
const char *pos;
u8 allowed_roles = DPP_CAPAB_CONFIGURATOR;
struct dpp_bootstrap_info *own_bi = NULL;
struct dpp_authentication *auth;
- if (!cmd)
- cmd = "";
+ wpas_dpp_pkex_clear_code(wpa_s);
+
+ os_snprintf(cmd, sizeof(cmd), " peer=%u %s", peer_bi->id,
+ wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)",
cmd);
@@ -2766,7 +2879,11 @@
}
return dpp_tcp_auth(wpa_s->dpp, conn, auth, wpa_s->conf->dpp_name,
- DPP_NETROLE_STA, wpas_dpp_process_conf_obj,
+ DPP_NETROLE_STA,
+ wpa_s->conf->dpp_mud_url,
+ wpa_s->conf->dpp_extra_conf_req_name,
+ wpa_s->conf->dpp_extra_conf_req_value,
+ wpas_dpp_process_conf_obj,
wpas_dpp_tcp_msg_sent);
}
#endif /* CONFIG_DPP2 */
@@ -2787,7 +2904,8 @@
wpa_s->dpp_pkex = NULL;
pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
wpa_s->dpp_pkex_identifier,
- wpa_s->dpp_pkex_code, v2);
+ wpa_s->dpp_pkex_code, wpa_s->dpp_pkex_code_len,
+ v2);
if (!pkex)
return -1;
pkex->forced_ver = ver != PKEX_VER_AUTO;
@@ -2946,6 +3064,14 @@
return;
}
+#ifdef CONFIG_DPP2
+ if (dpp_controller_is_own_pkex_req(wpa_s->dpp, buf, len)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX Exchange Request is from local Controller - ignore request");
+ return;
+ }
+#endif /* CONFIG_DPP2 */
+
if (wpa_s->dpp_pkex) {
/* TODO: Support parallel operations */
wpa_printf(MSG_DEBUG,
@@ -2957,6 +3083,7 @@
wpa_s->own_addr, src,
wpa_s->dpp_pkex_identifier,
wpa_s->dpp_pkex_code,
+ wpa_s->dpp_pkex_code_len,
buf, len, v2);
if (!wpa_s->dpp_pkex) {
wpa_printf(MSG_DEBUG,
@@ -2964,6 +3091,14 @@
return;
}
+#ifdef CONFIG_DPP3
+ if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_announcement) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Started PB PKEX (no more PB announcements)");
+ wpabuf_free(wpa_s->dpp_pb_announcement);
+ wpa_s->dpp_pb_announcement = NULL;
+ }
+#endif /* CONFIG_DPP3 */
wpa_s->dpp_pkex_wait_auth_req = false;
msg = wpa_s->dpp_pkex->exchange_resp;
wait_time = wpa_s->max_remain_on_chan;
@@ -3028,10 +3163,35 @@
{
struct dpp_bootstrap_info *bi;
+ wpas_dpp_pkex_clear_code(wpa_s);
bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq);
if (!bi)
return NULL;
+
wpa_s->dpp_pkex = NULL;
+
+#ifdef CONFIG_DPP3
+ if (wpa_s->dpp_pb_bi && !wpa_s->dpp_pb_configurator &&
+ os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_init_hash,
+ SHA256_MAC_LEN) != 0) {
+ char id[20];
+
+ wpa_printf(MSG_INFO,
+ "DPP: Peer bootstrap key from PKEX does not match PB announcement response hash");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB announcement response",
+ wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN);
+
+ os_snprintf(id, sizeof(id), "%u", bi->id);
+ dpp_bootstrap_remove(wpa_s->dpp, id);
+ wpas_dpp_push_button_stop(wpa_s);
+ return NULL;
+ }
+#endif /* CONFIG_DPP3 */
+
return bi;
}
@@ -3113,6 +3273,28 @@
if (!bi)
return;
+#ifdef CONFIG_DPP3
+ if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_configurator &&
+ os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_resp_hash,
+ SHA256_MAC_LEN) != 0) {
+ char id[20];
+
+ wpa_printf(MSG_INFO,
+ "DPP: Peer bootstrap key from PKEX does not match PB announcement hash");
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX",
+ bi->pubkey_hash_chirp, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Peer provided bootstrap key hash(chirp) from PB announcement",
+ wpa_s->dpp_pb_resp_hash, SHA256_MAC_LEN);
+
+ os_snprintf(id, sizeof(id), "%u", bi->id);
+ dpp_bootstrap_remove(wpa_s->dpp, id);
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
os_snprintf(cmd, sizeof(cmd), " peer=%u %s",
bi->id,
wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : "");
@@ -3128,6 +3310,588 @@
}
+#ifdef CONFIG_DPP3
+
+static void wpas_dpp_pb_pkex_init(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *src,
+ const u8 *r_hash)
+{
+ struct dpp_pkex *pkex;
+ struct wpabuf *msg;
+ unsigned int wait_time;
+ size_t len;
+
+ if (wpa_s->dpp_pkex) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Sending previously generated PKEX Exchange Request to "
+ MACSTR, MAC2STR(src));
+ msg = wpa_s->dpp_pkex->exchange_req;
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ offchannel_send_action(wpa_s, freq, src,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_pkex_status, 0);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Initiate PKEX for push button with "
+ MACSTR, MAC2STR(src));
+
+ if (!wpa_s->dpp_pb_cmd) {
+ wpa_printf(MSG_INFO,
+ "DPP: No configuration to provision as push button Configurator");
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi;
+ os_memcpy(wpa_s->dpp_pb_resp_hash, r_hash, SHA256_MAC_LEN);
+
+ pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr,
+ "PBPKEX", (const char *) wpa_s->dpp_pb_c_nonce,
+ wpa_s->dpp_pb_bi->curve->nonce_len,
+ true);
+ if (!pkex) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+ pkex->freq = freq;
+
+ wpa_s->dpp_pkex = pkex;
+ msg = wpa_s->dpp_pkex->exchange_req;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
+ " freq=%u type=%d", MAC2STR(src), freq,
+ DPP_PA_PKEX_EXCHANGE_REQ);
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ offchannel_send_action(wpa_s, pkex->freq, src,
+ wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_pkex_status, 0);
+ pkex->exch_req_wait_time = 2000;
+ pkex->exch_req_tries = 1;
+
+ /* Use the externally provided configuration */
+ os_free(wpa_s->dpp_pkex_auth_cmd);
+ len = 30 + os_strlen(wpa_s->dpp_pb_cmd);
+ wpa_s->dpp_pkex_auth_cmd = os_malloc(len);
+ if (wpa_s->dpp_pkex_auth_cmd)
+ os_snprintf(wpa_s->dpp_pkex_auth_cmd, len, " own=%d %s",
+ wpa_s->dpp_pkex_bi->id, wpa_s->dpp_pb_cmd);
+ else
+ wpas_dpp_push_button_stop(wpa_s);
+}
+
+
+static void
+wpas_dpp_rx_pb_presence_announcement(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *r_hash;
+ u16 r_hash_len;
+ unsigned int i;
+ bool found = false;
+ struct dpp_pb_info *info, *tmp;
+ struct os_reltime now, age;
+ struct wpabuf *msg;
+
+ os_get_reltime(&now);
+ wpa_printf(MSG_DEBUG, "DPP: Push Button Presence Announcement from "
+ MACSTR, MAC2STR(src));
+
+ r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_hash_len);
+ if (!r_hash || r_hash_len != SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_hash, r_hash_len);
+
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ info = &wpa_s->dpp_pb[i];
+ if ((info->rx_time.sec == 0 && info->rx_time.usec == 0) ||
+ os_memcmp(r_hash, info->hash, SHA256_MAC_LEN) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Active push button Enrollee already known");
+ found = true;
+ info->rx_time = now;
+ }
+
+ if (!found) {
+ for (i = 0; i < DPP_PB_INFO_COUNT; i++) {
+ tmp = &wpa_s->dpp_pb[i];
+ if (tmp->rx_time.sec == 0 && tmp->rx_time.usec == 0)
+ continue;
+
+ if (os_reltime_expired(&now, &tmp->rx_time, 120)) {
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Push button Enrollee hash expired",
+ tmp->hash, SHA256_MAC_LEN);
+ tmp->rx_time.sec = 0;
+ tmp->rx_time.usec = 0;
+ continue;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "DPP: Push button session overlap with hash",
+ tmp->hash, SHA256_MAC_LEN);
+ if (!wpa_s->dpp_pb_result_indicated &&
+ wpas_dpp_pb_active(wpa_s)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_PB_RESULT "session-overlap");
+ wpa_s->dpp_pb_result_indicated = true;
+ }
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ /* Replace the oldest entry */
+ info = &wpa_s->dpp_pb[0];
+ for (i = 1; i < DPP_PB_INFO_COUNT; i++) {
+ tmp = &wpa_s->dpp_pb[i];
+ if (os_reltime_before(&tmp->rx_time, &info->rx_time))
+ info = tmp;
+ }
+ wpa_printf(MSG_DEBUG, "DPP: New active push button Enrollee");
+ os_memcpy(info->hash, r_hash, SHA256_MAC_LEN);
+ info->rx_time = now;
+ }
+
+ if (!wpas_dpp_pb_active(wpa_s)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Discard message since own push button has not been pressed");
+ return;
+ }
+
+ if (wpa_s->dpp_pb_announce_time.sec == 0 &&
+ wpa_s->dpp_pb_announce_time.usec == 0) {
+ /* Start a wait before allowing PKEX to be initiated */
+ wpa_s->dpp_pb_announce_time = now;
+ }
+
+ if (!wpa_s->dpp_pb_bi) {
+ int res;
+
+ res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex");
+ if (res < 0)
+ return;
+ wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res);
+ if (!wpa_s->dpp_pb_bi)
+ return;
+
+ if (random_get_bytes(wpa_s->dpp_pb_c_nonce,
+ wpa_s->dpp_pb_bi->curve->nonce_len)) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to generate C-nonce");
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+ }
+
+ /* Skip the response if one was sent within last 50 ms since the
+ * Enrollee is going to send out at least three announcement messages.
+ */
+ os_reltime_sub(&now, &wpa_s->dpp_pb_last_resp, &age);
+ if (age.sec == 0 && age.usec < 50000) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Skip Push Button Presence Announcement Response frame immediately after having sent one");
+ return;
+ }
+
+ msg = dpp_build_pb_announcement_resp(
+ wpa_s->dpp_pb_bi, r_hash, wpa_s->dpp_pb_c_nonce,
+ wpa_s->dpp_pb_bi->curve->nonce_len);
+ if (!msg) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send Push Button Presence Announcement Response to "
+ MACSTR, MAC2STR(src));
+ wpa_s->dpp_pb_last_resp = now;
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(src), freq, DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP);
+ offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 0, NULL, 0);
+ wpabuf_free(msg);
+
+ if (os_reltime_expired(&now, &wpa_s->dpp_pb_announce_time, 15))
+ wpas_dpp_pb_pkex_init(wpa_s, freq, src, r_hash);
+}
+
+
+static void
+wpas_dpp_rx_pb_presence_announcement_resp(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *i_hash, *r_hash, *c_nonce;
+ u16 i_hash_len, r_hash_len, c_nonce_len;
+ bool overlap = false;
+
+ if (!wpa_s->dpp_pb_announcement || !wpa_s->dpp_pb_bi ||
+ wpa_s->dpp_pb_configurator) {
+ wpa_printf(MSG_INFO,
+ "DPP: Not in active push button Enrollee mode - discard Push Button Presence Announcement Response from "
+ MACSTR, MAC2STR(src));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Push Button Presence Announcement Response from "
+ MACSTR, MAC2STR(src));
+
+ i_hash = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
+ &i_hash_len);
+ r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
+ &r_hash_len);
+ c_nonce = dpp_get_attr(buf, len, DPP_ATTR_CONFIGURATOR_NONCE,
+ &c_nonce_len);
+ if (!i_hash || i_hash_len != SHA256_MAC_LEN ||
+ !r_hash || r_hash_len != SHA256_MAC_LEN ||
+ !c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Missing or invalid required attribute");
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
+ i_hash, i_hash_len);
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
+ r_hash, r_hash_len);
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator Nonce",
+ c_nonce, c_nonce_len);
+
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ &&
+ os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp,
+ SHA256_MAC_LEN - 1) == 0)
+ goto skip_hash_check;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp,
+ SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Unexpected push button Responder hash - abort");
+ overlap = true;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+skip_hash_check:
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_s->dpp_pb_resp_freq &&
+ os_memcmp(i_hash, wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_INFO,
+ "DPP: Push button session overlap detected - abort");
+ overlap = true;
+ }
+
+ if (overlap) {
+ if (!wpa_s->dpp_pb_result_indicated) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
+ "session-overlap");
+ wpa_s->dpp_pb_result_indicated = true;
+ }
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ if (!wpa_s->dpp_pb_resp_freq) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
+ "discovered push button AP/Configurator " MACSTR,
+ MAC2STR(src));
+ wpa_s->dpp_pb_resp_freq = freq;
+ os_memcpy(wpa_s->dpp_pb_init_hash, i_hash, SHA256_MAC_LEN);
+ os_memcpy(wpa_s->dpp_pb_c_nonce, c_nonce, c_nonce_len);
+ wpa_s->dpp_pb_c_nonce_len = c_nonce_len;
+ /* Stop announcement iterations after at least one more full
+ * round and one extra round for postponed session overlap
+ * detection. */
+ wpa_s->dpp_pb_stop_iter = 3;
+ }
+}
+
+
+static void
+wpas_dpp_tx_priv_intro_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ const char *res_txt;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
+ wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
+ " result=%s (DPP Private Peer Introduction Update)",
+ freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR " version=%u",
+ MAC2STR(src), wpa_s->dpp_intro_peer_version);
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Try connection again after successful network introduction");
+ if (wpa_supplicant_fast_associate(wpa_s) != 1) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+}
+
+
+static int
+wpas_dpp_send_private_peer_intro_update(struct wpa_supplicant *wpa_s,
+ struct dpp_introduction *intro,
+ struct wpa_ssid *ssid,
+ const u8 *dst, unsigned int freq)
+{
+ struct wpabuf *pt, *msg, *enc_ct;
+ size_t len;
+ u8 ver = DPP_VERSION;
+ int conn_ver;
+ const u8 *aad;
+ size_t aad_len;
+ unsigned int wait_time;
+
+ wpa_printf(MSG_DEBUG, "HPKE(kem_id=%u kdf_id=%u aead_id=%u)",
+ intro->kem_id, intro->kdf_id, intro->aead_id);
+
+ /* Plaintext for HPKE */
+ len = 5 + 4 + os_strlen(ssid->dpp_connector);
+ pt = wpabuf_alloc(len);
+ if (!pt)
+ return -1;
+
+ /* Protocol Version */
+ conn_ver = dpp_get_connector_version(ssid->dpp_connector);
+ if (conn_ver > 0 && ver != conn_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Use Connector version %d instead of current protocol version %d",
+ conn_ver, ver);
+ ver = conn_ver;
+ }
+ wpabuf_put_le16(pt, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(pt, 1);
+ wpabuf_put_u8(pt, ver);
+
+ /* Connector */
+ wpabuf_put_le16(pt, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(pt, os_strlen(ssid->dpp_connector));
+ wpabuf_put_str(pt, ssid->dpp_connector);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Plaintext for HPKE", pt);
+
+ /* HPKE(pt) using AP's public key (from its Connector) */
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, 0);
+ if (!msg) {
+ wpabuf_free(pt);
+ return -1;
+ }
+ aad = wpabuf_head_u8(msg) + 2; /* from the OUI field (inclusive) */
+ aad_len = DPP_HDR_LEN; /* to the DPP Frame Type field (inclusive) */
+ wpa_hexdump(MSG_MSGDUMP, "DPP: AAD for HPKE", aad, aad_len);
+
+ enc_ct = hpke_base_seal(intro->kem_id, intro->kdf_id, intro->aead_id,
+ intro->peer_key, NULL, 0, aad, aad_len,
+ wpabuf_head(pt), wpabuf_len(pt));
+ wpabuf_free(pt);
+ wpabuf_free(msg);
+ if (!enc_ct) {
+ wpa_printf(MSG_INFO, "DPP: HPKE Seal(Connector) failed");
+ return -1;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE enc|ct", enc_ct);
+
+ /* HPKE(pt) to generate payload for Wrapped Data */
+ len = 5 + 4 + wpabuf_len(enc_ct);
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, len);
+ if (!msg) {
+ wpabuf_free(enc_ct);
+ return -1;
+ }
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, TRANSACTION_ID);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(enc_ct));
+ wpabuf_put_buf(msg, enc_ct);
+ wpabuf_free(enc_ct);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Update", msg);
+
+ /* TODO: Timeout on AP response */
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(dst), freq, DPP_PA_PRIV_PEER_INTRO_QUERY);
+ offchannel_send_action(wpa_s, freq, dst, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_priv_intro_status, 0);
+ wpabuf_free(msg);
+
+ return 0;
+}
+
+
+static void
+wpas_dpp_rx_priv_peer_intro_notify(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpa_ssid *ssid;
+ const u8 *connector, *trans_id, *version;
+ u16 connector_len, trans_id_len, version_len;
+ u8 peer_version = 1;
+ struct dpp_introduction intro;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_time now;
+ struct os_reltime rnow;
+ os_time_t expiry;
+ unsigned int seconds;
+ enum dpp_status_error res;
+
+ os_memset(&intro, 0, sizeof(intro));
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Notify from "
+ MACSTR, MAC2STR(src));
+ if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
+ os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
+ MACSTR " - drop", MAC2STR(src));
+ return;
+ }
+ offchannel_send_action_done(wpa_s);
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->dpp_intro_network)
+ break;
+ }
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Profile not found for network introduction");
+ return;
+ }
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_transaction_id", MAC2STR(src));
+ goto fail;
+ }
+ if (trans_id[0] != TRANSACTION_ID) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore frame with unexpected Transaction ID %u",
+ trans_id[0]);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=transaction_id_mismatch", MAC2STR(src));
+ goto fail;
+ }
+
+ connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
+ if (!connector) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include its Connector");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_connector", MAC2STR(src));
+ goto fail;
+ }
+
+ version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (!version || version_len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include valid Version");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_version", MAC2STR(src));
+ goto fail;
+ }
+
+ res = dpp_peer_intro(&intro, ssid->dpp_connector,
+ ssid->dpp_netaccesskey,
+ ssid->dpp_netaccesskey_len,
+ ssid->dpp_csign,
+ ssid->dpp_csign_len,
+ connector, connector_len, &expiry);
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in failure");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=peer_connector_validation_failed", MAC2STR(src));
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+ goto fail;
+ }
+
+ peer_version = version[0];
+ if (intro.peer_version && intro.peer_version >= 2 &&
+ peer_version != intro.peer_version) {
+ wpa_printf(MSG_INFO,
+ "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
+ intro.peer_version, peer_version);
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH);
+ goto fail;
+ }
+ wpa_s->dpp_intro_peer_version = peer_version;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ goto fail;
+ entry->dpp_pfs = peer_version >= 2;
+ os_memcpy(entry->aa, src, ETH_ALEN);
+ os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
+ os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
+ entry->pmk_len = intro.pmk_len;
+ entry->akmp = WPA_KEY_MGMT_DPP;
+ if (expiry) {
+ os_get_time(&now);
+ seconds = expiry - now.sec;
+ } else {
+ seconds = 86400 * 7;
+ }
+
+ if (wpas_dpp_send_private_peer_intro_update(wpa_s, &intro, ssid, src,
+ freq) < 0) {
+ os_free(entry);
+ goto fail;
+ }
+
+ os_get_reltime(&rnow);
+ entry->expiration = rnow.sec + seconds;
+ entry->reauth_time = rnow.sec + seconds;
+ entry->network_ctx = ssid;
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+
+ /* Association will be initiated from TX status handler for the Private
+ * Peer Intro Update: wpas_dpp_tx_priv_intro_status() */
+
+fail:
+ dpp_peer_intro_deinit(&intro);
+}
+
+#endif /* CONFIG_DPP3 */
+
+
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *buf, size_t len, unsigned int freq)
{
@@ -3151,6 +3915,15 @@
"DPP: Received DPP Public Action frame crypto suite %u type %d from "
MACSTR " freq=%u",
crypto_suite, type, MAC2STR(src), freq);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->dpp_discard_public_action &&
+ type != DPP_PA_PEER_DISCOVERY_RESP &&
+ type != DPP_PA_PRIV_PEER_INTRO_NOTIFY) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Discard received DPP Public Action frame");
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (crypto_suite != 1) {
wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u",
crypto_suite);
@@ -3230,6 +4003,20 @@
wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq);
break;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ case DPP_PA_PB_PRESENCE_ANNOUNCEMENT:
+ wpas_dpp_rx_pb_presence_announcement(wpa_s, src, hdr,
+ buf, len, freq);
+ break;
+ case DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP:
+ wpas_dpp_rx_pb_presence_announcement_resp(wpa_s, src, hdr,
+ buf, len, freq);
+ break;
+ case DPP_PA_PRIV_PEER_INTRO_NOTIFY:
+ wpas_dpp_rx_priv_peer_intro_notify(wpa_s, src, hdr,
+ buf, len, freq);
+ break;
+#endif /* CONFIG_DPP3 */
default:
wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type);
@@ -3433,7 +4220,8 @@
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (ok) {
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d",
+ auth->conf_resp_status);
wpas_notify_dpp_config_sent(wpa_s);
}
else {
@@ -3443,6 +4231,20 @@
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
wpabuf_free(resp);
+#ifdef CONFIG_DPP3
+ if (!wpa_s->dpp_pb_result_indicated && wpas_dpp_pb_active(wpa_s)) {
+ if (ok)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
+ "success");
+ else
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT
+ "could-not-connect");
+ wpa_s->dpp_pb_result_indicated = true;
+ if (ok)
+ wpas_dpp_remove_pb_hash(wpa_s);
+ wpas_dpp_push_button_stop(wpa_s);
+ }
+#endif /* CONFIG_DPP3 */
}
@@ -3493,6 +4295,63 @@
}
+#ifdef CONFIG_DPP3
+static int wpas_dpp_start_private_peer_intro(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct wpa_bss *bss)
+{
+ struct wpabuf *msg;
+ unsigned int wait_time;
+ size_t len;
+ u8 ver = DPP_VERSION;
+ int conn_ver;
+
+ len = 5 + 5;
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_QUERY, len);
+ if (!msg)
+ return -1;
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, TRANSACTION_ID);
+
+ conn_ver = dpp_get_connector_version(ssid->dpp_connector);
+ if (conn_ver > 0 && ver != conn_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Use Connector version %d instead of current protocol version %d",
+ conn_ver, ver);
+ ver = conn_ver;
+ }
+
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, ver);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Query", msg);
+
+ /* TODO: Timeout on AP response */
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(bss->bssid), bss->freq, DPP_PA_PRIV_PEER_INTRO_QUERY);
+ offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_introduction_status, 0);
+ wpabuf_free(msg);
+
+ /* Request this connection attempt to terminate - new one will be
+ * started when network introduction protocol completes */
+ os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
+ wpa_s->dpp_intro_network = ssid;
+ return 1;
+}
+#endif /* CONFIG_DPP3 */
+
+
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss)
{
@@ -3532,11 +4391,18 @@
}
wpa_printf(MSG_DEBUG,
- "DPP: Starting network introduction protocol to derive PMKSA for "
- MACSTR, MAC2STR(bss->bssid));
+ "DPP: Starting %snetwork introduction protocol to derive PMKSA for "
+ MACSTR,
+ ssid->dpp_connector_privacy ? "private " : "",
+ MAC2STR(bss->bssid));
if (wpa_s->wpa_state == WPA_SCANNING)
wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
+#ifdef CONFIG_DPP3
+ if (ssid->dpp_connector_privacy)
+ return wpas_dpp_start_private_peer_intro(wpa_s, ssid, bss);
+#endif /* CONFIG_DPP3 */
+
len = 5 + 4 + os_strlen(ssid->dpp_connector);
#ifdef CONFIG_DPP2
len += 5;
@@ -3726,6 +4592,7 @@
wpa_s->dpp_pkex_code = os_strdup(pos + 6);
if (!wpa_s->dpp_pkex_code)
return -1;
+ wpa_s->dpp_pkex_code_len = os_strlen(wpa_s->dpp_pkex_code);
pos = os_strstr(cmd, " ver=");
if (pos) {
@@ -3774,7 +4641,7 @@
return -1;
}
- if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code)
+ if ((id_val != 0 && id_val != 1))
return -1;
/* TODO: Support multiple PKEX entries */
@@ -3803,6 +4670,9 @@
wpa_s->dpp_pkex_wait_auth_req = false;
if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
+#ifdef CONFIG_DPP3
+ wpas_dpp_push_button_stop(wpa_s);
+#endif /* CONFIG_DPP3 */
}
@@ -4077,29 +4947,20 @@
}
-static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res)
+static int * wpas_dpp_presence_ann_channels(struct wpa_supplicant *wpa_s,
+ struct dpp_bootstrap_info *bi)
{
- struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
unsigned int i;
struct hostapd_hw_modes *mode;
int c;
struct wpa_bss *bss;
bool chan6 = wpa_s->hw.modes == NULL;
-
- if (!bi && !wpa_s->dpp_reconfig_ssid)
- return;
-
- wpa_s->dpp_chirp_scan_done = 1;
-
- os_free(wpa_s->dpp_chirp_freqs);
- wpa_s->dpp_chirp_freqs = NULL;
+ int *freqs = NULL;
/* Channels from own bootstrapping info */
if (bi) {
for (i = 0; i < bi->num_freq; i++)
- int_array_add_unique(&wpa_s->dpp_chirp_freqs,
- bi->freq[i]);
+ int_array_add_unique(&freqs, bi->freq[i]);
}
/* Preferred chirping channels */
@@ -4117,7 +4978,7 @@
}
}
if (chan6)
- int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+ int_array_add_unique(&freqs, 2437);
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
HOSTAPD_MODE_IEEE80211A, false);
@@ -4136,9 +4997,9 @@
chan149 = 1;
}
if (chan149)
- int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+ int_array_add_unique(&freqs, 5745);
else if (chan44)
- int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+ int_array_add_unique(&freqs, 5220);
}
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
@@ -4151,7 +5012,7 @@
HOSTAPD_CHAN_RADAR)) ||
chan->freq != 60480)
continue;
- int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+ int_array_add_unique(&freqs, 60480);
break;
}
}
@@ -4160,10 +5021,26 @@
* Connectivity element */
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
- int_array_add_unique(&wpa_s->dpp_chirp_freqs,
- bss->freq);
+ int_array_add_unique(&freqs, bss->freq);
}
+ return freqs;
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+
+ if (!bi && !wpa_s->dpp_reconfig_ssid)
+ return;
+
+ wpa_s->dpp_chirp_scan_done = 1;
+
+ os_free(wpa_s->dpp_chirp_freqs);
+ wpa_s->dpp_chirp_freqs = wpas_dpp_presence_ann_channels(wpa_s, bi);
+
if (!wpa_s->dpp_chirp_freqs ||
eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
wpas_dpp_chirp_stop(wpa_s);
@@ -4461,3 +5338,314 @@
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+
+#define DPP_PB_ANNOUNCE_PER_CHAN 3
+
+static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq);
+static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx);
+
+
+static void wpas_dpp_pb_tx_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to send push button announcement on %d MHz",
+ freq);
+ if (eloop_register_timeout(0, 0, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Push button announcement on %d MHz sent",
+ freq);
+ if (wpa_s->dpp_pb_discovery_done) {
+ wpa_s->dpp_pb_announce_count = 0;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait for push button announcement response and PKEX on %d MHz",
+ freq);
+ if (eloop_register_timeout(0, 500000, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ } else if (wpa_s->dpp_pb_announce_count >= DPP_PB_ANNOUNCE_PER_CHAN) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Wait for push button announcement response on %d MHz",
+ freq);
+ if (eloop_register_timeout(0, 50000, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ if (wpas_dpp_pb_announce(wpa_s, freq) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+}
+
+
+static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq)
+{
+ struct wpabuf *msg;
+ int type;
+
+ msg = wpa_s->dpp_pb_announcement;
+ if (!msg)
+ return -1;
+
+ wpa_s->dpp_pb_announce_count++;
+ wpa_printf(MSG_DEBUG,
+ "DPP: Send push button announcement %d/%d (%d MHz)",
+ wpa_s->dpp_pb_announce_count, DPP_PB_ANNOUNCE_PER_CHAN,
+ freq);
+
+ type = DPP_PA_PB_PRESENCE_ANNOUNCEMENT;
+ if (wpa_s->dpp_pb_announce_count == 1)
+ wpa_msg(wpa_s, MSG_INFO,
+ DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(broadcast), freq, type);
+ if (offchannel_send_action(
+ wpa_s, freq, broadcast, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ 1000, wpas_dpp_pb_tx_status, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct os_reltime now;
+ int freq;
+
+ if (!wpa_s->dpp_pb_freqs)
+ return;
+
+ os_get_reltime(&now);
+ offchannel_send_action_done(wpa_s);
+
+ if (os_reltime_expired(&now, &wpa_s->dpp_pb_time, 100)) {
+ wpa_printf(MSG_DEBUG, "DPP: Push button wait time expired");
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ if (wpa_s->dpp_pb_freq_idx >= int_array_len(wpa_s->dpp_pb_freqs)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Completed push button announcement round");
+ wpa_s->dpp_pb_freq_idx = 0;
+ if (wpa_s->dpp_pb_stop_iter > 0) {
+ wpa_s->dpp_pb_stop_iter--;
+
+ if (wpa_s->dpp_pb_stop_iter == 1) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
+ "wait for AP/Configurator to allow PKEX to be initiated");
+ if (eloop_register_timeout(10, 0,
+ wpas_dpp_pb_next,
+ wpa_s, NULL) < 0) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+ return;
+ }
+
+ if (wpa_s->dpp_pb_stop_iter == 0) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS
+ "start push button PKEX responder on the discovered channel (%d MHz)",
+ wpa_s->dpp_pb_resp_freq);
+ wpa_s->dpp_pb_discovery_done = true;
+
+ wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi;
+
+ os_free(wpa_s->dpp_pkex_code);
+ wpa_s->dpp_pkex_code = os_memdup(
+ wpa_s->dpp_pb_c_nonce,
+ wpa_s->dpp_pb_c_nonce_len);
+ wpa_s->dpp_pkex_code_len =
+ wpa_s->dpp_pb_c_nonce_len;
+
+ os_free(wpa_s->dpp_pkex_identifier);
+ wpa_s->dpp_pkex_identifier =
+ os_strdup("PBPKEX");
+
+ if (!wpa_s->dpp_pkex_code ||
+ !wpa_s->dpp_pkex_identifier) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+
+ wpa_s->dpp_pkex_ver = PKEX_VER_ONLY_2;
+
+ os_free(wpa_s->dpp_pkex_auth_cmd);
+ wpa_s->dpp_pkex_auth_cmd = NULL;
+ }
+ }
+ }
+
+ if (wpa_s->dpp_pb_discovery_done)
+ freq = wpa_s->dpp_pb_resp_freq;
+ else
+ freq = wpa_s->dpp_pb_freqs[wpa_s->dpp_pb_freq_idx++];
+ wpa_s->dpp_pb_announce_count = 0;
+ if (!wpa_s->dpp_pb_announcement) {
+ wpa_printf(MSG_DEBUG, "DPP: Push button announcements stopped");
+ return;
+ }
+ if (wpas_dpp_pb_announce(wpa_s, freq) < 0) {
+ wpas_dpp_push_button_stop(wpa_s);
+ return;
+ }
+}
+
+
+static void wpas_dpp_push_button_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Active push button Configurator mode expired");
+ wpas_dpp_push_button_stop(wpa_s);
+}
+
+
+static int wpas_dpp_push_button_configurator(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ wpa_s->dpp_pb_configurator = true;
+ wpa_s->dpp_pb_announce_time.sec = 0;
+ wpa_s->dpp_pb_announce_time.usec = 0;
+ str_clear_free(wpa_s->dpp_pb_cmd);
+ wpa_s->dpp_pb_cmd = NULL;
+ if (cmd) {
+ wpa_s->dpp_pb_cmd = os_strdup(cmd);
+ if (!wpa_s->dpp_pb_cmd)
+ return -1;
+ }
+ eloop_register_timeout(100, 0, wpas_dpp_push_button_expire,
+ wpa_s, NULL);
+
+ return 0;
+}
+
+
+static void wpas_dpp_pb_scan_res_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ if (!wpa_s->dpp_pb_time.sec && !wpa_s->dpp_pb_time.usec)
+ return;
+
+ os_free(wpa_s->dpp_pb_freqs);
+ wpa_s->dpp_pb_freqs = wpas_dpp_presence_ann_channels(wpa_s, NULL);
+
+ wpa_printf(MSG_DEBUG, "DPP: Scan completed for PB discovery");
+ if (!wpa_s->dpp_pb_freqs ||
+ eloop_register_timeout(0, 0, wpas_dpp_pb_next, wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+}
+
+
+int wpas_dpp_push_button(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int res;
+
+ if (!wpa_s->dpp)
+ return -1;
+ wpas_dpp_push_button_stop(wpa_s);
+ wpas_dpp_stop(wpa_s);
+ wpas_dpp_chirp_stop(wpa_s);
+
+ os_get_reltime(&wpa_s->dpp_pb_time);
+
+ if (cmd &&
+ (os_strstr(cmd, " role=configurator") ||
+ os_strstr(cmd, " conf=")))
+ return wpas_dpp_push_button_configurator(wpa_s, cmd);
+
+ wpa_s->dpp_pb_configurator = false;
+
+ wpa_s->dpp_pb_freq_idx = 0;
+
+ res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex");
+ if (res < 0)
+ return -1;
+ wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res);
+ if (!wpa_s->dpp_pb_bi)
+ return -1;
+
+ wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
+ wpa_s->dpp_qr_mutual = 0;
+ wpa_s->dpp_pb_announcement =
+ dpp_build_pb_announcement(wpa_s->dpp_pb_bi);
+ if (!wpa_s->dpp_pb_announcement)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Scan to create channel list for PB discovery");
+ 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);
+ return 0;
+}
+
+
+void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->dpp)
+ return;
+ os_free(wpa_s->dpp_pb_freqs);
+ wpa_s->dpp_pb_freqs = NULL;
+ wpabuf_free(wpa_s->dpp_pb_announcement);
+ wpa_s->dpp_pb_announcement = NULL;
+ if (wpa_s->dpp_pb_bi) {
+ char id[20];
+
+ os_snprintf(id, sizeof(id), "%u", wpa_s->dpp_pb_bi->id);
+ dpp_bootstrap_remove(wpa_s->dpp, id);
+ wpa_s->dpp_pb_bi = NULL;
+ if (!wpa_s->dpp_pb_result_indicated) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed");
+ wpa_s->dpp_pb_result_indicated = true;
+ }
+ }
+
+ wpa_s->dpp_pb_resp_freq = 0;
+ wpa_s->dpp_pb_stop_iter = 0;
+ wpa_s->dpp_pb_discovery_done = false;
+ os_free(wpa_s->dpp_pb_cmd);
+ wpa_s->dpp_pb_cmd = NULL;
+
+ eloop_cancel_timeout(wpas_dpp_pb_next, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_dpp_push_button_expire, wpa_s, NULL);
+ if (wpas_dpp_pb_active(wpa_s)) {
+ wpa_printf(MSG_DEBUG, "DPP: Stop active push button mode");
+ if (!wpa_s->dpp_pb_result_indicated)
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed");
+ }
+ wpa_s->dpp_pb_time.sec = 0;
+ wpa_s->dpp_pb_time.usec = 0;
+ dpp_pkex_free(wpa_s->dpp_pkex);
+ wpa_s->dpp_pkex = NULL;
+ os_free(wpa_s->dpp_pkex_auth_cmd);
+ wpa_s->dpp_pkex_auth_cmd = NULL;
+
+ wpa_s->dpp_pb_result_indicated = false;
+
+ str_clear_free(wpa_s->dpp_pb_cmd);
+ wpa_s->dpp_pb_cmd = NULL;
+
+ if (wpa_s->scan_res_handler == wpas_dpp_pb_scan_res_handler) {
+ wpas_abort_ongoing_scan(wpa_s);
+ wpa_s->scan_res_handler = NULL;
+ }
+}
+
+#endif /* CONFIG_DPP3 */
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 2b03a54..e2bdd9d 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -44,5 +44,7 @@
int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_conf_set(struct wpa_supplicant *wpa_s, const char *cmd);
+int wpas_dpp_push_button(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s);
#endif /* DPP_SUPPLICANT_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 237f4e0..6be117c 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -523,6 +523,14 @@
int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
struct wpa_signal_info *si);
+static inline int wpa_drv_mlo_signal_poll(struct wpa_supplicant *wpa_s,
+ struct wpa_mlo_signal_info *mlo_si)
+{
+ if (wpa_s->driver->mlo_signal_poll)
+ return wpa_s->driver->mlo_signal_poll(wpa_s->drv_priv, mlo_si);
+ return -1;
+}
+
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)
{
@@ -964,7 +972,7 @@
static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s,
enum wpa_driver_if_type if_type,
unsigned int *num,
- unsigned int *freq_list)
+ struct weighted_pcl *freq_list)
{
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->get_pref_freq_list_override)
@@ -1117,4 +1125,49 @@
return wpa_s->driver->dpp_listen(wpa_s->drv_priv, enable);
}
+static inline int wpa_drv_send_pasn_resp(struct wpa_supplicant *wpa_s,
+ struct pasn_auth *params)
+{
+ if (!wpa_s->driver->send_pasn_resp)
+ return -1;
+ return wpa_s->driver->send_pasn_resp(wpa_s->drv_priv, params);
+}
+
+static inline int wpa_drv_set_secure_ranging_ctx(struct wpa_supplicant *wpa_s,
+ const u8 *own_addr,
+ const u8 *peer_addr,
+ u32 cipher, u8 tk_len,
+ const u8 *tk,
+ u8 ltf_keyseed_len,
+ const u8 *ltf_keyseed,
+ u32 action)
+{
+ struct secure_ranging_params params;
+
+ if (!wpa_s->driver->set_secure_ranging_ctx)
+ return -1;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.action = action;
+ params.own_addr = own_addr;
+ params.peer_addr = peer_addr;
+ params.cipher = cipher;
+ params.tk_len = tk_len;
+ params.tk = tk;
+ params.ltf_keyseed_len = ltf_keyseed_len;
+ params.ltf_keyseed = ltf_keyseed;
+
+ return wpa_s->driver->set_secure_ranging_ctx(wpa_s->drv_priv, ¶ms);
+}
+
+static inline int
+wpas_drv_get_sta_mlo_info(struct wpa_supplicant *wpa_s,
+ struct driver_sta_mlo_info *mlo_info)
+{
+ if (!wpa_s->driver->get_sta_mlo_info)
+ return 0;
+
+ return wpa_s->driver->get_sta_mlo_info(wpa_s->drv_priv, mlo_info);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index f806895..efec31c 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -714,7 +714,7 @@
printf("Sending fake EAP-Request-Identity\n");
eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf,
- sizeof(*hdr) + 5);
+ sizeof(*hdr) + 5, FRAME_ENCRYPTION_UNKNOWN);
}
@@ -842,7 +842,8 @@
wpabuf_len(eap));
eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
(u8 *) dot1x,
- sizeof(*dot1x) + wpabuf_len(eap));
+ sizeof(*dot1x) + wpabuf_len(eap),
+ FRAME_ENCRYPTION_UNKNOWN);
os_free(dot1x);
}
}
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7234de4..aa01245 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -168,6 +168,21 @@
}
+static void wpa_supplicant_update_link_bss(struct wpa_supplicant *wpa_s,
+ u8 link_id, const u8 *bssid)
+{
+ struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+
+ if (!bss) {
+ wpa_supplicant_update_scan_results(wpa_s);
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+ }
+
+ if (bss)
+ wpa_s->links[link_id].bss = bss;
+}
+
+
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid, *old_ssid;
@@ -286,6 +301,19 @@
}
+static void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ if (!wpa_s->valid_links)
+ return;
+
+ wpa_s->valid_links = 0;
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
+ wpa_s->links[i].bss = NULL;
+}
+
+
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
{
int bssid_changed;
@@ -338,6 +366,7 @@
wpa_s->current_ssid = NULL;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->key_mgmt = 0;
+ wpa_s->allowed_key_mgmts = 0;
wpas_rrm_reset(wpa_s);
wpa_s->wnmsleep_used = 0;
@@ -352,6 +381,8 @@
if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
wpa_s->enabled_4addr_mode = 0;
+
+ wpas_reset_mlo_info(wpa_s);
}
@@ -2801,6 +2832,28 @@
return -1;
}
+ /*
+ * Update PMK in wpa_sm and the driver if roamed to WPA/WPA2 PSK from a
+ * different AKM.
+ */
+ if (wpa_s->key_mgmt != ie.key_mgmt &&
+ wpa_key_mgmt_wpa_psk_no_sae(ie.key_mgmt)) {
+ if (!ssid->psk_set) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "No PSK available for association");
+ wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
+ return -1;
+ }
+
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, NULL);
+ if (wpa_s->conf->key_mgmt_offload &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD) &&
+ wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, ssid->psk,
+ PMK_LEN, KEY_FLAG_PMK))
+ wpa_dbg(wpa_s, MSG_ERROR,
+ "WPA: Cannot set PMK for key management offload");
+ }
+
wpa_s->key_mgmt = ie.key_mgmt;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT %s and proto %d",
@@ -3023,7 +3076,8 @@
get_supported_channel_width(&req_elems);
enum chan_width ap_operation_chan_width =
get_operation_channel_width(&resp_elems);
- if (wpa_s->connection_vht || wpa_s->connection_he) {
+ if (wpa_s->connection_vht || wpa_s->connection_he ||
+ wpa_s->connection_eht) {
wpa_s->connection_channel_bandwidth =
get_sta_operation_chan_width(ap_operation_chan_width,
sta_supported_chan_width);
@@ -3391,6 +3445,60 @@
}
+static int wpa_drv_get_mlo_info(struct wpa_supplicant *wpa_s)
+{
+ struct driver_sta_mlo_info mlo;
+ int i;
+
+ mlo.valid_links = 0;
+ if (wpas_drv_get_sta_mlo_info(wpa_s, &mlo)) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get MLO link info");
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ return -1;
+ }
+
+ if (wpa_s->valid_links == mlo.valid_links) {
+ bool match = true;
+
+ if (!mlo.valid_links)
+ return 0;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(mlo.valid_links & BIT(i)))
+ continue;
+
+ if (os_memcmp(wpa_s->links[i].addr, mlo.links[i].addr,
+ ETH_ALEN) != 0 ||
+ os_memcmp(wpa_s->links[i].bssid, mlo.links[i].bssid,
+ ETH_ALEN) != 0) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match &&
+ os_memcmp(wpa_s->ap_mld_addr, mlo.ap_mld_addr,
+ ETH_ALEN) == 0)
+ return 0;
+ }
+
+ wpa_s->valid_links = mlo.valid_links;
+ 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;
+
+ 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;
+ wpa_supplicant_update_link_bss(wpa_s, i, mlo.links[i].bssid);
+ }
+
+ return 0;
+}
+
+
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -3450,6 +3558,13 @@
return;
}
+ if (wpa_drv_get_mlo_info(wpa_s) < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get MLO connection info");
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+
if (ft_completed &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION)) {
wpa_msg(wpa_s, MSG_INFO, "Attempt to roam to " MACSTR,
@@ -3473,14 +3588,22 @@
ft_completed = wpa_fils_is_completed(wpa_s->wpa);
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
- /* For driver based roaming, insert PSK during the initial association */
- if (is_zero_ether_addr(wpa_s->bssid) &&
- wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
- /* In case the driver wants to handle re-assocs, pass it down the PMK. */
- wpa_dbg(wpa_s, MSG_DEBUG, "Pass the PMK to the driver");
- wpa_sm_install_pmk(wpa_s->wpa);
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
+ /*
+ * For driver based roaming, insert PSK during
+ * the initial association
+ */
+ if (is_zero_ether_addr(wpa_s->bssid) &&
+ wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ /*
+ * In case the driver wants to handle re-assocs,
+ * pass it down the PMK.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG, "Pass the PMK to the driver");
+ wpa_sm_install_pmk(wpa_s->wpa);
+ }
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+#endif
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
@@ -3601,14 +3724,23 @@
eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
- /*
- * We are done; the driver will take care of RSN 4-way
- * handshake.
- */
- wpa_supplicant_cancel_auth_timeout(wpa_s);
- wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
- eapol_sm_notify_portValid(wpa_s->eapol, true);
- eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ if (already_authorized) {
+ /*
+ * We are done; the driver will take care of RSN 4-way
+ * handshake.
+ */
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ eapol_sm_notify_portValid(wpa_s->eapol, true);
+ eapol_sm_notify_eap_success(wpa_s->eapol, true);
+ } else {
+ /* Update port, WPA_COMPLETED state from
+ * EVENT_PORT_AUTHORIZED context when driver is done
+ * with 4way handshake.
+ */
+ wpa_msg(wpa_s, MSG_INFO, "ASSOC INFO: wait for driver port "
+ "authorized indication");
+ }
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
@@ -3665,7 +3797,8 @@
wpa_supplicant_rx_eapol(
wpa_s, wpa_s->pending_eapol_rx_src,
wpabuf_head(wpa_s->pending_eapol_rx),
- wpabuf_len(wpa_s->pending_eapol_rx));
+ wpabuf_len(wpa_s->pending_eapol_rx),
+ wpa_s->pending_eapol_encrypted);
}
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = NULL;
@@ -5390,6 +5523,39 @@
break;
#endif /* CONFIG_AP */
+ case EVENT_LINK_CH_SWITCH_STARTED:
+ case EVENT_LINK_CH_SWITCH:
+ if (!data || !wpa_s->current_ssid ||
+ !(wpa_s->valid_links & BIT(data->ch_switch.link_id)))
+ break;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ "%sfreq=%d link_id=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ event == EVENT_LINK_CH_SWITCH ?
+ WPA_EVENT_LINK_CHANNEL_SWITCH :
+ WPA_EVENT_LINK_CHANNEL_SWITCH_STARTED,
+ data->ch_switch.freq,
+ data->ch_switch.link_id,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ channel_width_to_string(data->ch_switch.ch_width),
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+ if (event == EVENT_LINK_CH_SWITCH_STARTED)
+ break;
+
+ wpa_s->links[data->ch_switch.link_id].freq =
+ data->ch_switch.freq;
+ if (wpa_s->links[data->ch_switch.link_id].bss &&
+ wpa_s->links[data->ch_switch.link_id].bss->freq !=
+ data->ch_switch.freq) {
+ wpa_s->links[data->ch_switch.link_id].bss->freq =
+ data->ch_switch.freq;
+ notify_bss_changes(
+ wpa_s, WPA_BSS_FREQ_CHANGED_FLAG,
+ wpa_s->links[data->ch_switch.link_id].bss);
+ }
+ break;
case EVENT_CH_SWITCH_STARTED:
case EVENT_CH_SWITCH:
if (!data || !wpa_s->current_ssid)
@@ -5647,7 +5813,8 @@
case EVENT_EAPOL_RX:
wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
data->eapol_rx.data,
- data->eapol_rx.data_len);
+ data->eapol_rx.data_len,
+ data->eapol_rx.encrypted);
break;
case EVENT_SIGNAL_CHANGE:
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
@@ -5923,6 +6090,11 @@
sme_external_auth_trigger(wpa_s, data);
#endif /* CONFIG_SAE */
break;
+#ifdef CONFIG_PASN
+ case EVENT_PASN_AUTH:
+ wpas_pasn_auth_trigger(wpa_s, &data->pasn_auth);
+ break;
+#endif /* CONFIG_PASN */
case EVENT_PORT_AUTHORIZED:
wpa_supplicant_event_port_authorized(wpa_s);
break;
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index a6172d6..802f120 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -30,6 +30,8 @@
#define GAS_QUERY_WAIT_TIME_INITIAL 1000
#define GAS_QUERY_WAIT_TIME_COMEBACK 150
+#define GAS_QUERY_MAX_COMEBACK_DELAY 60000
+
/**
* struct gas_query_pending - Pending GAS query
*/
@@ -589,6 +591,8 @@
if (pos + 2 > data + len)
return 0;
comeback_delay = WPA_GET_LE16(pos);
+ if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY)
+ comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY;
pos += 2;
/* Advertisement Protocol element */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 02e6390..874c2bf 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -772,7 +772,8 @@
static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn,
struct ibss_rsn_peer *peer,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
int supp;
u8 *tmp;
@@ -788,7 +789,7 @@
peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
MACSTR, MAC2STR(peer->addr));
- wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
+ wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len, encrypted);
} else {
if (ibss_rsn_is_auth_started(peer) == 0) {
wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
@@ -809,7 +810,8 @@
int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
struct ibss_rsn_peer *peer;
@@ -818,7 +820,8 @@
peer = ibss_rsn_get_peer(ibss_rsn, src_addr);
if (peer)
- return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len);
+ return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len,
+ encrypted);
if (ibss_rsn_eapol_dst_supp(buf, len) > 0) {
/*
@@ -836,7 +839,7 @@
IBSS_RSN_AUTH_EAPOL_BY_US);
return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
- buf, len);
+ buf, len, encrypted);
}
return 0;
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 626c543..cff45a7 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -57,7 +57,8 @@
int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
- const u8 *buf, size_t len);
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted);
void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
size_t len);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 9a459c2..6198bd7 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1065,9 +1065,15 @@
goto fail;
}
- if (cred->imsi_privacy_key && cred->imsi_privacy_key[0]) {
- if (wpa_config_set_quoted(ssid, "imsi_privacy_key",
- cred->imsi_privacy_key) < 0)
+ if (cred->imsi_privacy_cert && cred->imsi_privacy_cert[0]) {
+ if (wpa_config_set_quoted(ssid, "imsi_privacy_cert",
+ cred->imsi_privacy_cert) < 0)
+ goto fail;
+ }
+
+ if (cred->imsi_privacy_attr && cred->imsi_privacy_attr[0]) {
+ if (wpa_config_set_quoted(ssid, "imsi_privacy_attr",
+ cred->imsi_privacy_attr) < 0)
goto fail;
}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index b67396d..16530fb 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -643,18 +643,20 @@
switch (params->freq.bandwidth) {
case 80:
if (params->freq.center_freq2) {
- ssid->max_oper_chwidth = CHANWIDTH_80P80MHZ;
+ ssid->max_oper_chwidth =
+ CONF_OPER_CHWIDTH_80P80MHZ;
ssid->vht_center_freq2 =
params->freq.center_freq2;
} else {
- ssid->max_oper_chwidth = CHANWIDTH_80MHZ;
+ ssid->max_oper_chwidth =
+ CONF_OPER_CHWIDTH_80MHZ;
}
break;
case 160:
- ssid->max_oper_chwidth = CHANWIDTH_160MHZ;
+ ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_160MHZ;
break;
default:
- ssid->max_oper_chwidth = CHANWIDTH_USE_HT;
+ ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT;
break;
}
}
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 8e31824..a544c94 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -424,6 +424,10 @@
wpa_s->last_ssid = NULL;
if (wpa_s->current_ssid == ssid)
wpa_s->current_ssid = NULL;
+#if defined(CONFIG_SME) && defined(CONFIG_SAE)
+ if (wpa_s->sme.ext_auth_wpa_ssid == ssid)
+ wpa_s->sme.ext_auth_wpa_ssid = NULL;
+#endif /* CONFIG_SME && CONFIG_SAE */
if (wpa_s->wpa)
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s &&
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index bd53c5c..5dca8f7 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -470,8 +470,9 @@
* or used.
*/
if (wpas_sta_secondary_channel_offset(bss, ¤t, &chan) < 0 &&
- ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT,
- ¤t, &chan) == NUM_HOSTAPD_MODES)
+ ieee80211_freq_to_channel_ext(bss->freq, 0,
+ CONF_OPER_CHWIDTH_USE_HT, ¤t,
+ &chan) == NUM_HOSTAPD_MODES)
return 0;
/*
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 3c395e9..0bfb962 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -129,7 +129,7 @@
const u8 *ssid, size_t ssid_len);
static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
int *force_freq, int *pref_freq, int go,
- unsigned int *pref_freq_list,
+ struct weighted_pcl *pref_freq_list,
unsigned int *num_pref_freq);
static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len);
@@ -705,7 +705,8 @@
struct wpa_supplicant *go_wpa_s, *cli_wpa_s;
struct wpa_ssid *persistent_go;
int p2p_no_group_iface;
- unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+ struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+ unsigned int size;
wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
@@ -3832,6 +3833,10 @@
int flag = 0;
enum chan_allowed res, res2;
+ if (is_6ghz_op_class(op_class) && !is_6ghz_psc_frequency(
+ p2p_channel_to_freq(op_class, channel)))
+ return NOT_ALLOWED;
+
res2 = res = has_channel(wpa_s->global, mode, op_class, channel, &flag);
if (bw == BW40MINUS) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
@@ -4732,7 +4737,7 @@
static int wpas_p2p_get_pref_freq_list(void *ctx, int go,
unsigned int *len,
- unsigned int *freq_list)
+ struct weighted_pcl *freq_list)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -4742,6 +4747,7 @@
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
{
+ int ret = 0;
u8 addr[ETH_ALEN] = {0};
if (wpa_s->conf->p2p_device_random_mac_addr == 0)
@@ -4779,16 +4785,20 @@
wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address.");
}
- if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
+ ret = wpa_drv_set_mac_addr(wpa_s, addr);
+
+ if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to set random MAC address");
- return -EINVAL;
+ return ret;
}
- if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
+ ret = wpa_supplicant_update_mac_addr(wpa_s);
+
+ if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Could not update MAC address information");
- return -EINVAL;
+ return ret;
}
wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
@@ -5708,7 +5718,7 @@
static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
int *force_freq, int *pref_freq, int go,
- unsigned int *pref_freq_list,
+ struct weighted_pcl *pref_freq_list,
unsigned int *num_pref_freq)
{
struct wpa_used_freq_data *freqs;
@@ -5822,16 +5832,19 @@
i = 0;
while (i < *num_pref_freq &&
(!p2p_supported_freq(wpa_s->global->p2p,
- pref_freq_list[i]) ||
- wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]))) {
+ pref_freq_list[i].freq) ||
+ wpas_p2p_disallowed_freq(
+ wpa_s->global,
+ pref_freq_list[i].freq) ||
+ !p2p_pref_freq_allowed(&pref_freq_list[i],
+ go))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
- i, pref_freq_list[i]);
+ i, pref_freq_list[i].freq);
i++;
}
if (i != *num_pref_freq) {
- best_freq = pref_freq_list[i];
+ best_freq = pref_freq_list[i].freq;
wpa_printf(MSG_DEBUG,
"P2P: Using preferred_freq_list[%d]=%d",
i, best_freq);
@@ -5955,7 +5968,8 @@
enum wpa_driver_if_type iftype;
const u8 *if_addr;
struct wpa_ssid *ssid = NULL;
- unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+ struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+ unsigned int size;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -6240,7 +6254,7 @@
if (!wpa_s->conf->num_p2p_pref_chan && !freq) {
unsigned int i, size = P2P_MAX_PREF_CHANNELS;
- unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
+ struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
int res;
res = wpa_drv_get_pref_freq_list(wpa_s, WPA_IF_P2P_GO,
@@ -6252,16 +6266,19 @@
i = 0;
while (i < size &&
(!p2p_supported_freq(wpa_s->global->p2p,
- pref_freq_list[i]) ||
- wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]))) {
+ pref_freq_list[i].freq) ||
+ wpas_p2p_disallowed_freq(
+ wpa_s->global,
+ pref_freq_list[i].freq) ||
+ !p2p_pref_freq_allowed(&pref_freq_list[i],
+ true))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
- i, pref_freq_list[i]);
+ i, pref_freq_list[i].freq);
i++;
}
if (i != size) {
- freq = pref_freq_list[i];
+ freq = pref_freq_list[i].freq;
wpa_printf(MSG_DEBUG,
"P2P: Using preferred_freq_list[%d]=%d",
i, freq);
@@ -6740,8 +6757,8 @@
if (!is_6ghz &&
ieee80211_freq_to_channel_ext(
- cand, -1, CHANWIDTH_USE_HT, &op_class,
- &chan) != NUM_HOSTAPD_MODES &&
+ cand, -1, CONF_OPER_CHWIDTH_USE_HT,
+ &op_class, &chan) != NUM_HOSTAPD_MODES &&
wpas_p2p_verify_channel(
wpa_s, hwmode, op_class, chan,
BW40MINUS) == ALLOWED)
@@ -6749,8 +6766,8 @@
if (!supported && !is_6ghz &&
ieee80211_freq_to_channel_ext(
- cand, 1, CHANWIDTH_USE_HT, &op_class,
- &chan) != NUM_HOSTAPD_MODES &&
+ cand, 1, CONF_OPER_CHWIDTH_USE_HT,
+ &op_class, &chan) != NUM_HOSTAPD_MODES &&
wpas_p2p_verify_channel(
wpa_s, hwmode, op_class, chan,
BW40PLUS) == ALLOWED)
@@ -6896,6 +6913,7 @@
bool allow_6ghz)
{
struct p2p_go_neg_results params;
+ int selected_freq = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
@@ -6910,12 +6928,12 @@
wpas_p2p_stop_find_oper(wpa_s);
if (!wpa_s->p2p_go_do_acs) {
- freq = wpas_p2p_select_go_freq(wpa_s, freq);
- if (freq < 0)
+ selected_freq = wpas_p2p_select_go_freq(wpa_s, freq);
+ if (selected_freq < 0)
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 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;
@@ -6926,6 +6944,8 @@
wpa_s = wpas_p2p_get_group_iface(wpa_s, 0, 1);
if (wpa_s == NULL)
return -1;
+ if (freq > 0)
+ wpa_s->p2p_go_no_pri_sec_switch = 1;
wpas_start_wps_go(wpa_s, ¶ms, 0);
return 0;
@@ -6937,6 +6957,8 @@
int freq, int force_scan)
{
struct wpa_ssid *ssid;
+ int other_iface_found = 0;
+ struct wpa_supplicant *ifs;
wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
if (wpa_s == NULL)
@@ -6981,6 +7003,26 @@
wpa_s->p2p_go_group_formation_completed = 0;
wpa_s->global->p2p_group_formation = wpa_s;
+ /*
+ * Get latest scan results from driver in case cached scan results from
+ * interfaces on the same wiphy allow us to skip the next scan by fast
+ * associating. Also update the scan time to the most recent scan result
+ * 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);
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ if (ifs == wpa_s)
+ continue;
+ if (!other_iface_found || os_reltime_before(&wpa_s->last_scan,
+ &ifs->last_scan)) {
+ other_iface_found = 1;
+ wpa_s->last_scan.sec = ifs->last_scan.sec;
+ wpa_s->last_scan.usec = ifs->last_scan.usec;
+ }
+ }
+
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev,
NULL);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
@@ -7045,6 +7087,7 @@
freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
if (freq < 0)
return -1;
+ wpa_s->p2p_go_no_pri_sec_switch = 1;
} else {
freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
if (freq < 0 ||
@@ -7636,7 +7679,8 @@
int force_freq = 0;
int res;
int no_pref_freq_given = pref_freq == 0;
- unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+ struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+ unsigned int size;
if (wpas_p2p_check_6ghz(wpa_s, NULL, allow_6ghz, freq))
return -1;
@@ -7725,7 +7769,8 @@
int persistent;
int freq = 0, force_freq = 0, pref_freq = 0;
int res;
- unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size;
+ struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS];
+ unsigned int size;
wpa_s->p2p_persistent_go_freq = 0;
wpa_s->p2p_go_ht40 = 0;
@@ -9660,9 +9705,6 @@
if (!wpa_s->conf->p2p_optimize_listen_chan)
return;
- if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED)
- return;
-
curr_chan = p2p_get_listen_channel(wpa_s->global->p2p);
for (i = 0, cand = 0; i < num; i++) {
ieee80211_freq_to_chan(freqs[i].freq, &chan);
@@ -9732,10 +9774,13 @@
if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode &&
(wpa_s->ap_iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A ||
+ is_6ghz_freq(wpa_s->ap_iface->freq) ||
conf->hw_mode != HOSTAPD_MODE_IEEE80211G)) {
wpa_dbg(wpa_s, MSG_INFO,
- "P2P CSA: CSA from Hardware mode %d to %d is not supported",
- wpa_s->ap_iface->current_mode->mode, conf->hw_mode);
+ "P2P CSA: CSA from hardware mode %d%s to %d is not supported",
+ wpa_s->ap_iface->current_mode->mode,
+ is_6ghz_freq(wpa_s->ap_iface->freq) ? " (6 GHz)" : "",
+ conf->hw_mode);
ret = -1;
goto out;
}
@@ -9784,13 +9829,15 @@
csa_settings.freq_params.center_freq2 = freq2;
switch (conf->vht_oper_chwidth) {
- case CHANWIDTH_80MHZ:
- case CHANWIDTH_80P80MHZ:
+ case CONF_OPER_CHWIDTH_80MHZ:
+ case CONF_OPER_CHWIDTH_80P80MHZ:
csa_settings.freq_params.bandwidth = 80;
break;
- case CHANWIDTH_160MHZ:
+ case CONF_OPER_CHWIDTH_160MHZ:
csa_settings.freq_params.bandwidth = 160;
break;
+ default:
+ break;
}
}
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index dc21b6a..2e6d9a7 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -23,11 +23,13 @@
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "bss.h"
+#include "scan.h"
#include "config.h"
static const int dot11RSNAConfigPMKLifetime = 43200;
struct wpa_pasn_auth_work {
+ u8 own_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
int akmp;
int cipher;
@@ -52,6 +54,8 @@
wpa_printf(MSG_DEBUG, "PASN: Auth work timeout - stopping auth");
wpas_pasn_auth_stop(wpa_s);
+
+ wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
}
@@ -111,7 +115,7 @@
}
ret = sae_prepare_commit_pt(&pasn->sae, pasn->ssid->pt,
- wpa_s->own_addr, pasn->bssid,
+ pasn->own_addr, pasn->bssid,
NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
@@ -286,6 +290,281 @@
#endif /* CONFIG_SAE */
+static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
+ struct pasn_peer *peer)
+{
+ int ret;
+ const u8 *rsne, *rsnxe;
+ struct wpa_bss *bss;
+ struct wpa_ie_data rsne_data;
+ int sel, key_mgmt, pairwise_cipher;
+ int network_id = 0, group = 19;
+ struct wpa_ssid *ssid = NULL;
+ size_t ssid_str_len = 0;
+ const u8 *ssid_str = NULL;
+ const u8 *bssid = peer->peer_addr;
+
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_supplicant_update_scan_results(wpa_s);
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS not found");
+ return -1;
+ }
+ }
+
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (!rsne) {
+ wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
+ return -1;
+ }
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+
+ ssid_str_len = bss->ssid_len;
+ ssid_str = bss->ssid;
+
+ /* Get the network configuration based on the obtained SSID */
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!wpas_network_disabled(wpa_s, ssid) &&
+ ssid_str_len == ssid->ssid_len &&
+ os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
+ break;
+ }
+
+ if (ssid)
+ network_id = ssid->id;
+
+ sel = rsne_data.pairwise_cipher;
+ if (ssid && ssid->pairwise_cipher)
+ sel &= ssid->pairwise_cipher;
+
+ wpa_printf(MSG_DEBUG, "PASN: peer pairwise 0x%x, select 0x%x",
+ rsne_data.pairwise_cipher, sel);
+
+ pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
+ if (pairwise_cipher < 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "PASN: Failed to select pairwise cipher");
+ return -1;
+ }
+
+ sel = rsne_data.key_mgmt;
+ if (ssid && ssid->key_mgmt)
+ sel &= ssid->key_mgmt;
+
+ wpa_printf(MSG_DEBUG, "PASN: peer AKMP 0x%x, select 0x%x",
+ rsne_data.key_mgmt, sel);
+#ifdef CONFIG_SAE
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) || !ssid)
+ sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
+ WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
+ sel &= ~WPA_KEY_MGMT_FT;
+#endif /* CONFIG_IEEE80211R */
+ if (0) {
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SHA384
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
+ key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X-SHA384");
+ if (ssid && !ssid->ft_eap_pmksa_caching &&
+ pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT may have interoperability
+ * issues, so disable that case by default for now.
+ */
+ wpa_printf(MSG_DEBUG,
+ "PASN: Disable PMKSA caching for FT/802.1X connection");
+ pmksa_cache_clear_current(wpa_s->wpa);
+ }
+#endif /* CONFIG_SHA384 */
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ } else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) &&
+ (ieee802_11_rsnx_capab(rsnxe,
+ WLAN_RSNX_CAPAB_SAE_H2E)) &&
+ (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) == 0)) {
+ key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE (ext key)");
+ } else if ((sel & WPA_KEY_MGMT_SAE) &&
+ (ieee802_11_rsnx_capab(rsnxe,
+ WLAN_RSNX_CAPAB_SAE_H2E)) &&
+ (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) == 0)) {
+ key_mgmt = WPA_KEY_MGMT_SAE;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE");
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
+ key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA384");
+ } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
+ key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA256");
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
+ os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
+ key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X");
+ if (ssid && !ssid->ft_eap_pmksa_caching &&
+ pmksa_cache_get_current(wpa_s->wpa)) {
+ /* PMKSA caching with FT may have interoperability
+ * issues, so disable that case by default for now.
+ */
+ wpa_printf(MSG_DEBUG,
+ "PASN: Disable PMKSA caching for FT/802.1X connection");
+ pmksa_cache_clear_current(wpa_s->wpa);
+ }
+ } else if (sel & WPA_KEY_MGMT_FT_PSK) {
+ key_mgmt = WPA_KEY_MGMT_FT_PSK;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/PSK");
+#endif /* CONFIG_IEEE80211R */
+ } else if (sel & WPA_KEY_MGMT_PASN) {
+ key_mgmt = WPA_KEY_MGMT_PASN;
+ wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT PASN");
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: invalid AKMP");
+ return -1;
+ }
+
+ peer->akmp = key_mgmt;
+ peer->cipher = pairwise_cipher;
+ peer->network_id = network_id;
+ peer->group = group;
+ return 0;
+}
+
+
+static int wpas_pasn_set_keys_from_cache(struct wpa_supplicant *wpa_s,
+ const u8 *own_addr, const u8 *bssid,
+ int cipher, int akmp)
+{
+ struct ptksa_cache_entry *entry;
+
+ entry = ptksa_cache_get(wpa_s->ptksa, bssid, cipher);
+ if (!entry) {
+ wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
+ " not present in PTKSA cache", MAC2STR(bssid));
+ return -1;
+ }
+
+ if (os_memcmp(entry->own_addr, own_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: own addr " MACSTR " and PTKSA entry own addr "
+ MACSTR " differ",
+ MAC2STR(own_addr), MAC2STR(entry->own_addr));
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
+ MAC2STR(bssid));
+ wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, bssid, cipher,
+ entry->ptk.tk_len,
+ entry->ptk.tk,
+ entry->ptk.ltf_keyseed_len,
+ entry->ptk.ltf_keyseed, 0);
+ return 0;
+}
+
+
+static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
+ struct pasn_auth *pasn_params)
+{
+ struct pasn_peer *peer;
+ u8 comeback_len = 0;
+ const u8 *comeback = NULL;
+
+ if (!pasn_params)
+ return;
+
+ while (wpa_s->pasn_count < pasn_params->num_peers) {
+ peer = &pasn_params->peer[wpa_s->pasn_count];
+
+ if (os_memcmp(wpa_s->bssid, peer->peer_addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Associated peer is not expected");
+ peer->status = PASN_STATUS_FAILURE;
+ wpa_s->pasn_count++;
+ continue;
+ }
+
+ if (wpas_pasn_set_keys_from_cache(wpa_s, peer->own_addr,
+ peer->peer_addr,
+ peer->cipher,
+ peer->akmp) == 0) {
+ peer->status = PASN_STATUS_SUCCESS;
+ wpa_s->pasn_count++;
+ continue;
+ }
+
+ if (wpas_pasn_get_params_from_bss(wpa_s, peer)) {
+ peer->status = PASN_STATUS_FAILURE;
+ wpa_s->pasn_count++;
+ continue;
+ }
+
+ if (wpas_pasn_auth_start(wpa_s, peer->own_addr,
+ peer->peer_addr, peer->akmp,
+ peer->cipher, peer->group,
+ peer->network_id,
+ comeback, comeback_len)) {
+ peer->status = PASN_STATUS_FAILURE;
+ wpa_s->pasn_count++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "PASN: Sent PASN auth start for " MACSTR,
+ MAC2STR(peer->peer_addr));
+ return;
+ }
+
+ if (wpa_s->pasn_count == pasn_params->num_peers) {
+ wpa_drv_send_pasn_resp(wpa_s, pasn_params);
+ wpa_printf(MSG_DEBUG, "PASN: Response sent");
+ os_free(wpa_s->pasn_params);
+ wpa_s->pasn_params = NULL;
+ }
+}
+
+
+void wpas_pasn_auth_work_done(struct wpa_supplicant *wpa_s, int status)
+{
+ if (!wpa_s->pasn_params)
+ return;
+
+ wpa_s->pasn_params->peer[wpa_s->pasn_count].status = status;
+ wpa_s->pasn_count++;
+ wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params);
+}
+
+
+static void wpas_pasn_delete_peers(struct wpa_supplicant *wpa_s,
+ struct pasn_auth *pasn_params)
+{
+ struct pasn_peer *peer;
+ unsigned int i;
+
+ if (!pasn_params)
+ return;
+
+ for (i = 0; i < pasn_params->num_peers; i++) {
+ peer = &pasn_params->peer[i];
+ wpas_pasn_deauthenticate(wpa_s, peer->own_addr,
+ peer->peer_addr);
+ }
+}
+
+
#ifdef CONFIG_FILS
static struct wpabuf * wpas_pasn_fils_build_auth(struct wpa_supplicant *wpa_s)
@@ -685,7 +964,7 @@
wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
wpa_pasn_build_auth_header(buf, pasn->bssid,
- wpa_s->own_addr, pasn->bssid,
+ pasn->own_addr, pasn->bssid,
pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
pmkid = NULL;
@@ -732,11 +1011,11 @@
/* Add own RNSXE */
capab = 0;
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
- if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
- if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA)
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
- if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
wpa_pasn_add_rsnxe(buf, capab);
@@ -788,7 +1067,7 @@
wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
wpa_pasn_build_auth_header(buf, pasn->bssid,
- wpa_s->own_addr, pasn->bssid,
+ pasn->own_addr, pasn->bssid,
pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
@@ -816,7 +1095,7 @@
data_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
- wpa_s->own_addr, pasn->bssid,
+ pasn->own_addr, pasn->bssid,
pasn->hash, mic_len * 2, data, data_len, mic);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed MIC calculation");
@@ -990,9 +1269,9 @@
}
-static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int akmp, int cipher, u16 group, int freq,
- const u8 *beacon_rsne, u8 beacon_rsne_len,
+static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *own_addr,
+ const u8 *bssid, int akmp, int cipher, u16 group,
+ int freq, const u8 *beacon_rsne, u8 beacon_rsne_len,
const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
int network_id, struct wpabuf *comeback)
{
@@ -1080,7 +1359,7 @@
pasn->group = group;
pasn->freq = freq;
- derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
+ derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
ieee802_11_rsnx_capab(beacon_rsnxe,
WLAN_RSNX_CAPAB_SECURE_LTF);
#ifdef CONFIG_TESTING_OPTIONS
@@ -1093,6 +1372,13 @@
pasn->kdk_len = 0;
wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
+ if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
+ ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
+ pasn->secure_ltf = true;
+ else
+ pasn->secure_ltf = false;
+
+ os_memcpy(pasn->own_addr, own_addr, ETH_ALEN);
os_memcpy(pasn->bssid, bssid, ETH_ALEN);
wpa_printf(MSG_DEBUG,
@@ -1207,8 +1493,9 @@
rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
- ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
- awork->group, bss->freq, rsne, *(rsne + 1) + 2,
+ ret = wpas_pasn_start(wpa_s, awork->own_addr, awork->bssid, awork->akmp,
+ awork->cipher, awork->group, bss->freq,
+ rsne, *(rsne + 1) + 2,
rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
awork->network_id, awork->comeback);
if (ret) {
@@ -1230,7 +1517,8 @@
}
-int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
+int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
+ const u8 *own_addr, const u8 *bssid,
int akmp, int cipher, u16 group, int network_id,
const u8 *comeback, size_t comeback_len)
{
@@ -1272,6 +1560,7 @@
if (!awork)
return -1;
+ os_memcpy(awork->own_addr, own_addr, ETH_ALEN);
os_memcpy(awork->bssid, bssid, ETH_ALEN);
awork->akmp = akmp;
awork->cipher = cipher;
@@ -1321,19 +1610,29 @@
int akmp = pasn->akmp;
int cipher = pasn->cipher;
u16 group = pasn->group;
+ u8 own_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
int network_id = pasn->ssid ? pasn->ssid->id : 0;
wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
+ os_memcpy(own_addr, pasn->own_addr, ETH_ALEN);
os_memcpy(bssid, pasn->bssid, ETH_ALEN);
wpas_pasn_reset(wpa_s);
- return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group,
+ return wpas_pasn_auth_start(wpa_s, own_addr, bssid, akmp, cipher, group,
network_id,
params->comeback, params->comeback_len);
}
+static void wpas_pasn_deauth_cb(struct ptksa_cache_entry *entry)
+{
+ struct wpa_supplicant *wpa_s = entry->ctx;
+
+ wpas_pasn_deauthenticate(wpa_s, entry->own_addr, entry->addr);
+}
+
+
int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -1358,7 +1657,7 @@
return -2;
/* Not our frame; do nothing */
- if (os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN) != 0 ||
+ if (os_memcmp(mgmt->da, pasn->own_addr, ETH_ALEN) != 0 ||
os_memcmp(mgmt->sa, pasn->bssid, ETH_ALEN) != 0 ||
os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN) != 0)
return -2;
@@ -1382,9 +1681,7 @@
status != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
wpa_printf(MSG_DEBUG,
"PASN: Authentication rejected - status=%u", status);
- pasn->status = status;
- wpas_pasn_auth_stop(wpa_s);
- return -1;
+ goto fail;
}
if (ieee802_11_parse_elems(mgmt->u.auth.variable,
@@ -1518,7 +1815,7 @@
}
ret = pasn_pmk_to_ptk(pasn->pmk, pasn->pmk_len,
- wpa_s->own_addr, pasn->bssid,
+ pasn->own_addr, pasn->bssid,
wpabuf_head(secret), wpabuf_len(secret),
&pasn->ptk, pasn->akmp, pasn->cipher,
pasn->kdk_len);
@@ -1527,6 +1824,15 @@
goto fail;
}
+ if (pasn->secure_ltf) {
+ ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to derive LTF keyseed");
+ goto fail;
+ }
+ }
+
wpabuf_free(wrapped_data);
wrapped_data = NULL;
wpabuf_free(secret);
@@ -1534,7 +1840,7 @@
/* Verify the MIC */
ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
- pasn->bssid, wpa_s->own_addr,
+ pasn->bssid, pasn->own_addr,
wpabuf_head(pasn->beacon_rsne_rsnxe),
wpabuf_len(pasn->beacon_rsne_rsnxe),
(u8 *) &mgmt->u.auth,
@@ -1567,8 +1873,10 @@
wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
- ptksa_cache_add(wpa_s->ptksa, pasn->bssid, pasn->cipher,
- dot11RSNAConfigPMKLifetime, &pasn->ptk);
+ ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->bssid,
+ pasn->cipher, dot11RSNAConfigPMKLifetime, &pasn->ptk,
+ wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL,
+ wpa_s->pasn_params ? wpa_s : NULL);
forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
@@ -1590,10 +1898,65 @@
pasn->status = status;
wpas_pasn_auth_stop(wpa_s);
+
+ wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
return -1;
}
+void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s,
+ struct pasn_auth *pasn_auth)
+{
+ struct pasn_peer *src, *dst;
+ unsigned int i, num_peers = pasn_auth->num_peers;
+
+ if (wpa_s->pasn_params) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth_trigger: Already in progress");
+ return;
+ }
+
+ if (!num_peers || num_peers > WPAS_MAX_PASN_PEERS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth trigger: Invalid number of peers");
+ return;
+ }
+
+ wpa_s->pasn_params = os_zalloc(sizeof(struct pasn_auth));
+ if (!wpa_s->pasn_params) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth trigger: Failed to allocate a buffer");
+ return;
+ }
+
+ wpa_s->pasn_count = 0;
+ wpa_s->pasn_params->num_peers = num_peers;
+
+ for (i = 0; i < num_peers; i++) {
+ dst = &wpa_s->pasn_params->peer[i];
+ src = &pasn_auth->peer[i];
+ os_memcpy(dst->own_addr, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(dst->peer_addr, src->peer_addr, ETH_ALEN);
+ dst->ltf_keyseed_required = src->ltf_keyseed_required;
+ dst->status = PASN_STATUS_SUCCESS;
+
+ if (!is_zero_ether_addr(src->own_addr)) {
+ os_memcpy(dst->own_addr, src->own_addr, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "PASN: Own (source) MAC addr: "
+ MACSTR, MAC2STR(dst->own_addr));
+ }
+ }
+
+ if (pasn_auth->action == PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT) {
+ wpas_pasn_delete_peers(wpa_s, wpa_s->pasn_params);
+ os_free(wpa_s->pasn_params);
+ wpa_s->pasn_params = NULL;
+ } else if (pasn_auth->action == PASN_ACTION_AUTH) {
+ wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params);
+ }
+}
+
+
int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
const u8 *data, size_t data_len, u8 acked)
@@ -1621,7 +1984,7 @@
/* Not our frame; do nothing */
if (os_memcmp(mgmt->da, pasn->bssid, ETH_ALEN) ||
- os_memcmp(mgmt->sa, wpa_s->own_addr, ETH_ALEN) ||
+ os_memcmp(mgmt->sa, pasn->own_addr, ETH_ALEN) ||
os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN))
return -1;
@@ -1653,14 +2016,25 @@
* Either frame was not ACKed or it was ACKed but the trans_seq
* != 1, i.e., not expecting an RX frame, so we are done.
*/
+ if (!wpa_s->pasn_params) {
+ wpas_pasn_auth_stop(wpa_s);
+ return 0;
+ }
+
+ wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr,
+ pasn->bssid, pasn->cipher,
+ pasn->akmp);
wpas_pasn_auth_stop(wpa_s);
+
+ wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS);
}
return 0;
}
-int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr,
+ const u8 *bssid)
{
struct wpa_bss *bss;
struct wpabuf *buf;
@@ -1673,6 +2047,9 @@
return -1;
}
+ wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, bssid, 0, 0, NULL, 0,
+ NULL, 1);
+
wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries for "
MACSTR, MAC2STR(bssid));
ptksa_cache_flush(wpa_s->ptksa, bssid, WPA_CIPHER_NONE);
@@ -1696,7 +2073,7 @@
(WLAN_FC_STYPE_DEAUTH << 4));
os_memcpy(deauth->da, bssid, ETH_ALEN);
- os_memcpy(deauth->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(deauth->sa, own_addr, ETH_ALEN);
os_memcpy(deauth->bssid, bssid, ETH_ALEN);
deauth->u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
index 6110797..a561891 100644
--- a/wpa_supplicant/robust_av.c
+++ b/wpa_supplicant/robust_av.c
@@ -706,14 +706,15 @@
static int write_ipv4_info(char *pos, int total_len,
- const struct ipv4_params *v4)
+ const struct ipv4_params *v4,
+ u8 classifier_mask)
{
int res, rem_len;
char addr[INET_ADDRSTRLEN];
rem_len = total_len;
- if (v4->param_mask & BIT(1)) {
+ if (classifier_mask & BIT(1)) {
if (!inet_ntop(AF_INET, &v4->src_ip, addr, INET_ADDRSTRLEN)) {
wpa_printf(MSG_ERROR,
"QM: Failed to set IPv4 source address");
@@ -728,7 +729,7 @@
rem_len -= res;
}
- if (v4->param_mask & BIT(2)) {
+ if (classifier_mask & BIT(2)) {
if (!inet_ntop(AF_INET, &v4->dst_ip, addr, INET_ADDRSTRLEN)) {
wpa_printf(MSG_ERROR,
"QM: Failed to set IPv4 destination address");
@@ -743,7 +744,7 @@
rem_len -= res;
}
- if (v4->param_mask & BIT(3)) {
+ if (classifier_mask & BIT(3)) {
res = os_snprintf(pos, rem_len, " src_port=%d", v4->src_port);
if (os_snprintf_error(rem_len, res))
return -1;
@@ -752,7 +753,7 @@
rem_len -= res;
}
- if (v4->param_mask & BIT(4)) {
+ if (classifier_mask & BIT(4)) {
res = os_snprintf(pos, rem_len, " dst_port=%d", v4->dst_port);
if (os_snprintf_error(rem_len, res))
return -1;
@@ -761,7 +762,7 @@
rem_len -= res;
}
- if (v4->param_mask & BIT(6)) {
+ if (classifier_mask & BIT(6)) {
res = os_snprintf(pos, rem_len, " protocol=%d", v4->protocol);
if (os_snprintf_error(rem_len, res))
return -1;
@@ -775,14 +776,15 @@
static int write_ipv6_info(char *pos, int total_len,
- const struct ipv6_params *v6)
+ const struct ipv6_params *v6,
+ u8 classifier_mask)
{
int res, rem_len;
char addr[INET6_ADDRSTRLEN];
rem_len = total_len;
- if (v6->param_mask & BIT(1)) {
+ if (classifier_mask & BIT(1)) {
if (!inet_ntop(AF_INET6, &v6->src_ip, addr, INET6_ADDRSTRLEN)) {
wpa_printf(MSG_ERROR,
"QM: Failed to set IPv6 source addr");
@@ -797,7 +799,7 @@
rem_len -= res;
}
- if (v6->param_mask & BIT(2)) {
+ if (classifier_mask & BIT(2)) {
if (!inet_ntop(AF_INET6, &v6->dst_ip, addr, INET6_ADDRSTRLEN)) {
wpa_printf(MSG_ERROR,
"QM: Failed to set IPv6 destination addr");
@@ -812,7 +814,7 @@
rem_len -= res;
}
- if (v6->param_mask & BIT(3)) {
+ if (classifier_mask & BIT(3)) {
res = os_snprintf(pos, rem_len, " src_port=%d", v6->src_port);
if (os_snprintf_error(rem_len, res))
return -1;
@@ -821,7 +823,7 @@
rem_len -= res;
}
- if (v6->param_mask & BIT(4)) {
+ if (classifier_mask & BIT(4)) {
res = os_snprintf(pos, rem_len, " dst_port=%d", v6->dst_port);
if (os_snprintf_error(rem_len, res))
return -1;
@@ -830,7 +832,7 @@
rem_len -= res;
}
- if (v6->param_mask & BIT(6)) {
+ if (classifier_mask & BIT(6)) {
res = os_snprintf(pos, rem_len, " protocol=%d",
v6->next_header);
if (os_snprintf_error(rem_len, res))
@@ -861,7 +863,7 @@
/* Classifier Mask - bit 1 = Source IP Address */
if (classifier_mask & BIT(1)) {
- type4_param->ip_params.v4.param_mask |= BIT(1);
+ type4_param->classifier_mask |= BIT(1);
os_memcpy(&type4_param->ip_params.v4.src_ip,
&frame_classifier[3], 4);
}
@@ -874,14 +876,14 @@
return -1;
}
- type4_param->ip_params.v4.param_mask |= BIT(2);
+ type4_param->classifier_mask |= BIT(2);
os_memcpy(&type4_param->ip_params.v4.dst_ip,
&frame_classifier[7], 4);
}
/* Classifier Mask - bit 3 = Source Port */
if (classifier_mask & BIT(3)) {
- type4_param->ip_params.v4.param_mask |= BIT(3);
+ type4_param->classifier_mask |= BIT(3);
type4_param->ip_params.v4.src_port =
WPA_GET_BE16(&frame_classifier[11]);
}
@@ -894,7 +896,7 @@
return -1;
}
- type4_param->ip_params.v4.param_mask |= BIT(4);
+ type4_param->classifier_mask |= BIT(4);
type4_param->ip_params.v4.dst_port =
WPA_GET_BE16(&frame_classifier[13]);
}
@@ -903,7 +905,7 @@
/* Classifier Mask - bit 6 = Protocol */
if (classifier_mask & BIT(6)) {
- type4_param->ip_params.v4.param_mask |= BIT(6);
+ type4_param->classifier_mask |= BIT(6);
type4_param->ip_params.v4.protocol = frame_classifier[16];
}
@@ -928,7 +930,7 @@
/* Classifier Mask - bit 1 = Source IP Address */
if (classifier_mask & BIT(1)) {
- type4_param->ip_params.v6.param_mask |= BIT(1);
+ type4_param->classifier_mask |= BIT(1);
os_memcpy(&type4_param->ip_params.v6.src_ip,
&frame_classifier[3], 16);
}
@@ -940,14 +942,14 @@
"QM: IPv6: Both domain name and destination IP address not expected");
return -1;
}
- type4_param->ip_params.v6.param_mask |= BIT(2);
+ type4_param->classifier_mask |= BIT(2);
os_memcpy(&type4_param->ip_params.v6.dst_ip,
&frame_classifier[19], 16);
}
/* Classifier Mask - bit 3 = Source Port */
if (classifier_mask & BIT(3)) {
- type4_param->ip_params.v6.param_mask |= BIT(3);
+ type4_param->classifier_mask |= BIT(3);
type4_param->ip_params.v6.src_port =
WPA_GET_BE16(&frame_classifier[35]);
}
@@ -960,7 +962,7 @@
return -1;
}
- type4_param->ip_params.v6.param_mask |= BIT(4);
+ type4_param->classifier_mask |= BIT(4);
type4_param->ip_params.v6.dst_port =
WPA_GET_BE16(&frame_classifier[37]);
}
@@ -969,7 +971,7 @@
/* Classifier Mask - bit 6 = Next Header */
if (classifier_mask & BIT(6)) {
- type4_param->ip_params.v6.param_mask |= BIT(6);
+ type4_param->classifier_mask |= BIT(6);
type4_param->ip_params.v6.next_header = frame_classifier[40];
}
@@ -1075,9 +1077,11 @@
}
if (type4->ip_version == IPV4)
- res = write_ipv4_info(pos, len, &type4->ip_params.v4);
+ res = write_ipv4_info(pos, len, &type4->ip_params.v4,
+ type4->classifier_mask);
else
- res = write_ipv6_info(pos, len, &type4->ip_params.v6);
+ res = write_ipv6_info(pos, len, &type4->ip_params.v6,
+ type4->classifier_mask);
if (res <= 0) {
wpa_printf(MSG_ERROR,
@@ -1294,11 +1298,17 @@
attr = qos_ie + 6;
rem_attrs_len = qos_ie[1] - 4;
- while (rem_attrs_len > 2 && rem_attrs_len >= 2 + attr[1]) {
- wpas_fill_dscp_policy(&policy, attr[0], attr[1],
- &attr[2]);
- rem_attrs_len -= 2 + attr[1];
- attr += 2 + attr[1];
+ while (rem_attrs_len > 2) {
+ u8 attr_id, attr_len;
+
+ attr_id = *attr++;
+ attr_len = *attr++;
+ rem_attrs_len -= 2;
+ if (attr_len > rem_attrs_len)
+ break;
+ wpas_fill_dscp_policy(&policy, attr_id, attr_len, attr);
+ rem_attrs_len -= attr_len;
+ attr += attr_len;
}
rem_len -= ie_len;
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index 4457b6c..238fe68 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -731,24 +731,24 @@
vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
switch (vht_oper->vht_op_info_chwidth) {
- case 1:
+ case CHANWIDTH_80MHZ:
seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
if (seg1 && abs(seg1 - seg0) == 8)
- vht = CHANWIDTH_160MHZ;
+ vht = CONF_OPER_CHWIDTH_160MHZ;
else if (seg1)
- vht = CHANWIDTH_80P80MHZ;
+ vht = CONF_OPER_CHWIDTH_80P80MHZ;
else
- vht = CHANWIDTH_80MHZ;
+ vht = CONF_OPER_CHWIDTH_80MHZ;
break;
- case 2:
- vht = CHANWIDTH_160MHZ;
+ case CHANWIDTH_160MHZ:
+ vht = CONF_OPER_CHWIDTH_160MHZ;
break;
- case 3:
- vht = CHANWIDTH_80P80MHZ;
+ case CHANWIDTH_80P80MHZ:
+ vht = CONF_OPER_CHWIDTH_80P80MHZ;
break;
default:
- vht = CHANWIDTH_USE_HT;
+ vht = CONF_OPER_CHWIDTH_USE_HT;
break;
}
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index a683eac..ee90aac 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1036,19 +1036,6 @@
}
#ifdef CONFIG_P2P
-#ifdef ANDROID
- if (wpa_s->global->p2p_go_found_external_scan &&
- (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) &&
- (wpa_s->global->p2p_group_formation == wpa_s)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Try to fast associate since GO is found in external scan");
- wpa_s->global->p2p_go_found_external_scan = 0;
- if (wpa_supplicant_fast_associate(wpa_s) >= 0) {
- return;
- }
- }
-#endif
-
if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
wpa_s->go_params && !wpa_s->conf->passive_scan) {
wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
@@ -1341,6 +1328,12 @@
}
}
+ if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
+ wpa_s->manual_non_coloc_6ghz) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Collocated 6 GHz logic is disabled");
+ params.non_coloc_6ghz = 1;
+ }
+
scan_params = ¶ms;
scan:
@@ -1378,8 +1371,6 @@
(wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning) &&
!is_p2p_allow_6ghz(wpa_s->global->p2p) &&
is_6ghz_supported(wpa_s)) {
- int i;
-
/* Exclude 6 GHz channels from the full scan for P2P connection
* since the 6 GHz band is disabled for P2P uses. */
wpa_printf(MSG_DEBUG,
@@ -1939,6 +1930,18 @@
}
+const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type)
+{
+ size_t ie_len = res->ie_len;
+
+ /* Use the Beacon frame IEs if res->ie_len is not available */
+ if (!ie_len)
+ ie_len = res->beacon_ie_len;
+
+ return get_ml_ie((const u8 *) (res + 1), ie_len, type);
+}
+
+
/**
* wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
* @res: Scan result entry
@@ -2915,6 +2918,7 @@
params->relative_adjust_band = src->relative_adjust_band;
params->relative_adjust_rssi = src->relative_adjust_rssi;
params->p2p_include_6ghz = src->p2p_include_6ghz;
+ params->non_coloc_6ghz = src->non_coloc_6ghz;
return params;
failed:
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index d1780eb..f826d91 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -51,6 +51,7 @@
struct scan_info *info, int new_scan);
int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
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,
u32 vendor_type);
const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index cc55fa6..a847e2f 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -72,6 +72,7 @@
if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
wpa_s->sme.sae.group);
+ wpa_s->sme.sae.akmp = wpa_s->key_mgmt;
return 0;
}
wpa_s->sme.sae_group_index++;
@@ -153,6 +154,9 @@
if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
use_pt = 1;
+ if (wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt) &&
+ wpa_s->conf->sae_pwe != 3)
+ use_pt = 1;
#ifdef CONFIG_SAE_PK
if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
ssid->sae_pk != SAE_PK_MODE_DISABLED &&
@@ -174,7 +178,8 @@
if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
- if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id ||
+ wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
wpa_s->conf->sae_pwe != 3 &&
!use_pt) {
wpa_printf(MSG_DEBUG,
@@ -749,9 +754,9 @@
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
NULL,
- wpa_s->key_mgmt == WPA_KEY_MGMT_FT_SAE ?
- WPA_KEY_MGMT_FT_SAE :
- WPA_KEY_MGMT_SAE) == 0) {
+ wpa_key_mgmt_sae(wpa_s->key_mgmt) ?
+ wpa_s->key_mgmt :
+ (int) WPA_KEY_MGMT_SAE) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -1112,6 +1117,7 @@
{
struct external_auth params;
+ wpa_s->sme.ext_auth_wpa_ssid = NULL;
os_memset(¶ms, 0, sizeof(params));
params.status = status;
params.ssid = wpa_s->sme.ext_auth_ssid;
@@ -1130,13 +1136,18 @@
size_t ssid_str_len = data->external_auth.ssid_len;
const u8 *ssid_str = data->external_auth.ssid;
+ wpa_s->sme.ext_auth_wpa_ssid = NULL;
/* Get the SSID conf from the ssid string obtained */
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (!wpas_network_disabled(wpa_s, ssid) &&
ssid_str_len == ssid->ssid_len &&
os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
- (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)))
+ wpa_key_mgmt_sae(ssid->key_mgmt)) {
+ /* Make sure PT is derived */
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ wpa_s->sme.ext_auth_wpa_ssid = ssid;
break;
+ }
}
if (!ssid ||
sme_external_auth_send_sae_commit(wpa_s, data->external_auth.bssid,
@@ -1263,7 +1274,8 @@
if (auth_transaction == 1 &&
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
- (external || wpa_s->current_bss) && wpa_s->current_ssid) {
+ ((external && wpa_s->sme.ext_auth_wpa_ssid) ||
+ (!external && wpa_s->current_bss && wpa_s->current_ssid))) {
int default_groups[] = { 19, 20, 21, 0 };
u16 group;
const u8 *token_pos;
@@ -1297,21 +1309,24 @@
token_len = len - sizeof(le16);
h2e = wpa_s->sme.sae.h2e;
if (h2e) {
+ u8 id, elen, extid;
+
if (token_len < 3) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Too short SAE anti-clogging token container");
return -1;
}
- if (token_pos[0] != WLAN_EID_EXTENSION ||
- token_pos[1] == 0 ||
- token_pos[1] > token_len - 2 ||
- token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
+ id = *token_pos++;
+ elen = *token_pos++;
+ extid = *token_pos++;
+ if (id != WLAN_EID_EXTENSION ||
+ elen == 0 || elen > token_len - 2 ||
+ extid != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Invalid SAE anti-clogging token container header");
return -1;
}
- token_len = token_pos[1] - 1;
- token_pos += 3;
+ token_len = elen - 1;
}
wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
@@ -1322,14 +1337,15 @@
else
sme_external_auth_send_sae_commit(
wpa_s, wpa_s->sme.ext_auth_bssid,
- wpa_s->current_ssid);
+ wpa_s->sme.ext_auth_wpa_ssid);
return 0;
}
if (auth_transaction == 1 &&
status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
- (external || wpa_s->current_bss) && wpa_s->current_ssid) {
+ ((external && wpa_s->sme.ext_auth_wpa_ssid) ||
+ (!external && wpa_s->current_bss && wpa_s->current_ssid))) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
wpa_s->sme.sae.group);
@@ -1343,7 +1359,7 @@
else
sme_external_auth_send_sae_commit(
wpa_s, wpa_s->sme.ext_auth_bssid,
- wpa_s->current_ssid);
+ wpa_s->sme.ext_auth_wpa_ssid);
return 0;
}
@@ -1375,8 +1391,9 @@
groups = wpa_s->conf->sae_groups;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
- if ((!external && wpa_s->current_bss == NULL) ||
- wpa_s->current_ssid == NULL)
+ if ((external && !wpa_s->sme.ext_auth_wpa_ssid) ||
+ (!external &&
+ (!wpa_s->current_bss || !wpa_s->current_ssid)))
return -1;
if (wpa_s->sme.sae.state != SAE_COMMITTED) {
wpa_printf(MSG_DEBUG,
@@ -1463,7 +1480,7 @@
{
wpa_printf(MSG_DEBUG,
"SME: SAE completed - setting PMK for 4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, wpa_s->sme.sae.pmk_len,
wpa_s->sme.sae.pmkid, bssid);
if (wpa_s->conf->sae_pmkid_in_assoc) {
/* Update the own RSNE contents now that we have set the PMK
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4c7e6dc..5393f1c 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -921,7 +921,8 @@
{
const u8 *ie;
u8 op_class, chan;
- int sec_chan = 0, vht = 0;
+ int sec_chan = 0;
+ enum oper_chan_width vht = CONF_OPER_CHWIDTH_USE_HT;
enum phy_type phy_type;
u32 info;
struct ieee80211_ht_operation *ht_oper = NULL;
@@ -1457,15 +1458,22 @@
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
char url[256];
+ u8 url_len;
- if (end - pos < 1 || 1 + pos[0] > end - pos) {
+ if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
"Management Request (URL)");
return;
}
- os_memcpy(url, pos + 1, pos[0]);
- url[pos[0]] = '\0';
- pos += 1 + pos[0];
+ url_len = *pos++;
+ if (url_len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Invalid BSS Transition Management Request (URL truncated)");
+ return;
+ }
+ os_memcpy(url, pos, url_len);
+ url[url_len] = '\0';
+ pos += url_len;
wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
wpa_sm_pmf_enabled(wpa_s->wpa),
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 0e2315d..197efe0 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -413,6 +413,18 @@
}
+static int wpa_cli_cmd_mlo_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "MLO_STATUS");
+}
+
+
+static int wpa_cli_cmd_mlo_signal_poll(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "MLO_SIGNAL_POLL");
+}
+
+
static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -3134,7 +3146,7 @@
static int wpa_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+ return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv);
}
@@ -3159,6 +3171,15 @@
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_DPP3
+static int wpa_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv);
+}
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
@@ -3994,6 +4015,11 @@
cli_cmd_flag_none,
"= stop DPP chirp" },
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ { "dpp_push_button", wpa_cli_cmd_dpp_push_button, NULL,
+ cli_cmd_flag_none,
+ "= press DPP push button" },
+#endif /* CONFIG_DPP3 */
#endif /* CONFIG_DPP */
{ "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
"= list all BSS entries (scan results)" },
@@ -4023,6 +4049,12 @@
{ "dscp_query", wpa_cli_cmd_dscp_query, NULL,
cli_cmd_flag_none,
"wildcard/domain_name=<string> = Send DSCP Query" },
+ { "mlo_status", wpa_cli_cmd_mlo_status, NULL,
+ cli_cmd_flag_none,
+ "= get MLO status" },
+ { "mlo_signal_poll", wpa_cli_cmd_mlo_signal_poll, NULL,
+ cli_cmd_flag_none,
+ "= get mlo signal parameters" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index c5d7168..ff1fb67 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -1134,7 +1134,8 @@
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
struct wpa_priv_interface *iface = ctx;
struct msghdr msg;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 05766b5..17bb231 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -17,6 +17,7 @@
#endif /* CONFIG_MATCH_IFACE */
#include "common.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/sha1.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -985,6 +986,13 @@
if (state == WPA_COMPLETED && wpa_s->new_connection) {
struct wpa_ssid *ssid = wpa_s->current_ssid;
int fils_hlp_sent = 0;
+ char mld_addr[50];
+
+ mld_addr[0] = '\0';
+ if (wpa_s->valid_links)
+ os_snprintf(mld_addr, sizeof(mld_addr),
+ " ap_mld_addr=" MACSTR,
+ MAC2STR(wpa_s->ap_mld_addr));
#ifdef CONFIG_SME
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
@@ -997,11 +1005,11 @@
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed [id=%d id_str=%s%s]",
+ MACSTR " completed [id=%d id_str=%s%s]%s",
MAC2STR(wpa_s->bssid),
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "",
- fils_hlp_sent ? " FILS_HLP_SENT" : "");
+ fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr);
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpa_s->consecutive_conn_failures = 0;
@@ -1122,6 +1130,7 @@
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
+ wpa_s->allowed_key_mgmts = 0;
if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
wpa_supplicant_set_state(wpa_s, new_state);
@@ -1342,6 +1351,111 @@
}
+static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ int akm_count = wpa_s->max_num_akms;
+ u8 capab = 0;
+
+ if (akm_count < 2)
+ return;
+
+ akm_count--;
+ wpa_s->allowed_key_mgmts = 0;
+ switch (wpa_s->key_mgmt) {
+ case WPA_KEY_MGMT_PSK:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_PSK_SHA256:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ break;
+ case WPA_KEY_MGMT_SAE:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ case WPA_KEY_MGMT_SAE_EXT_KEY:
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ akm_count--;
+ wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK;
+ }
+ if (!akm_count)
+ break;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+ wpa_s->allowed_key_mgmts |=
+ WPA_KEY_MGMT_PSK_SHA256;
+ break;
+ default:
+ return;
+ }
+
+ if (wpa_s->conf->sae_pwe)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (ssid->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+
+ if (!((wpa_s->allowed_key_mgmts &
+ (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab))
+ return;
+
+ if (!wpa_s->rsnxe_len) {
+ wpa_s->rsnxe_len = 3;
+ wpa_s->rsnxe[0] = WLAN_EID_RSNX;
+ wpa_s->rsnxe[1] = 1;
+ wpa_s->rsnxe[2] = 0;
+ }
+
+ wpa_s->rsnxe[2] |= capab;
+}
+
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -1542,7 +1656,8 @@
sel = ie.key_mgmt & ssid->key_mgmt;
#ifdef CONFIG_SAE
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
- sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+ sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211R
if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
@@ -1587,13 +1702,15 @@
} else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
- } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
#endif /* CONFIG_IEEE80211R */
} else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
+#ifdef CONFIG_IEEE80211R
+ } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
+#endif /* CONFIG_IEEE80211R */
} else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
@@ -1618,6 +1735,13 @@
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
#endif /* CONFIG_DPP */
#ifdef CONFIG_SAE
+ } else if (sel & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RSN: using KEY_MGMT FT/SAE (ext key)");
+ } else if (sel & WPA_KEY_MGMT_SAE_EXT_KEY) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE (ext key)");
} else if (sel & WPA_KEY_MGMT_FT_SAE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
@@ -1682,7 +1806,9 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
sae_pwe = wpa_s->conf->sae_pwe;
- if (ssid->sae_password_id && sae_pwe != 3)
+ if ((ssid->sae_password_id ||
+ wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
+ sae_pwe != 3)
sae_pwe = 1;
if (bss && is_6ghz_freq(bss->freq)) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hash-to-element mode for 6GHz BSS.");
@@ -1915,6 +2041,10 @@
wpa_dbg(wpa_s, MSG_INFO,
"WPA: Updating to KEY_MGMT SAE+PSK for seamless roaming");
}
+#else
+ if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ wpas_update_allowed_key_mgmt(wpa_s, ssid);
#endif /* CONFIG_DRIVER_NL80211_BRCM */
return 0;
@@ -2160,7 +2290,7 @@
}
-static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
{
#ifdef CONFIG_SAE
int *groups = conf->sae_groups;
@@ -2176,6 +2306,7 @@
if (!password ||
(conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ !wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) &&
!sae_pk_valid_password(password)) ||
conf->sae_pwe == 3) {
/* PT derivation not needed */
@@ -2711,7 +2842,7 @@
if (!ibss_mesh_is_80mhz_avail(channel, mode))
return;
- chwidth = CHANWIDTH_80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80MHZ;
seg0 = channel + 6;
seg1 = 0;
@@ -2727,14 +2858,14 @@
for (j = 0; j < ARRAY_SIZE(bw160); j++) {
if (freq->freq == bw160[j]) {
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
seg0 = channel + 14;
break;
}
}
}
- if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
+ if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
/* setup center_freq2, bandwidth */
for (k = 0; k < ARRAY_SIZE(bw80); k++) {
/* Only accept 80 MHz segments separated by a gap */
@@ -2758,28 +2889,28 @@
continue;
/* Found a suitable second segment for 80+80 */
- chwidth = CHANWIDTH_80P80MHZ;
+ chwidth = CONF_OPER_CHWIDTH_80P80MHZ;
if (!is_6ghz)
vht_caps |=
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
seg1 = channel + 6;
}
- if (chwidth == CHANWIDTH_80P80MHZ)
+ if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ)
break;
}
- } else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
+ } else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
if (freq->freq == 5180) {
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 50;
} else if (freq->freq == 5520) {
- chwidth = CHANWIDTH_160MHZ;
+ chwidth = CONF_OPER_CHWIDTH_160MHZ;
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 114;
}
- } else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
- chwidth = CHANWIDTH_USE_HT;
+ } else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_USE_HT) {
+ chwidth = CONF_OPER_CHWIDTH_USE_HT;
seg0 = channel + 2;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40)
@@ -3114,7 +3245,7 @@
#endif /* CONFIG_FILS */
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_SAE
- if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
+ if (wpa_key_mgmt_sae(wpa_s->key_mgmt))
algs = WPA_AUTH_ALG_SAE;
#endif /* CONFIG_SAE */
@@ -3800,6 +3931,11 @@
wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
}
+ /* Set current_ssid before changing state to ASSOCIATING, so that the
+ * selected SSID is available to wpas_notify_state_changed(). */
+ old_ssid = wpa_s->current_ssid;
+ wpa_s->current_ssid = ssid;
+
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
if (bss) {
params.ssid = bss->ssid;
@@ -3915,6 +4051,7 @@
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
params.key_mgmt_suite = wpa_s->key_mgmt;
+ params.allowed_key_mgmts = wpa_s->allowed_key_mgmts;
params.wpa_proto = wpa_s->wpa_proto;
wpa_s->auth_alg = params.auth_alg;
params.mode = ssid->mode;
@@ -3933,13 +4070,15 @@
#endif /* CONFIG_WEP */
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
- (
#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
+ ((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
+ (params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK))) {
#else
- params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
+ (params.allowed_key_mgmts &
+ (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
#endif /* CONFIG_DRIVER_NL80211_BRCM */
- params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
if (ssid->psk_set)
params.psk = ssid->psk;
@@ -3963,14 +4102,14 @@
else
params.req_key_mgmt_offload = 1;
- if ((
#ifdef CONFIG_DRIVER_NL80211_BRCM
- (params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
-#else
- params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+ if (((params.key_mgmt_suite & WPA_KEY_MGMT_PSK) ||
params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
+#else
+ if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
+ wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
ssid->psk_set)
params.psk = ssid->psk;
}
@@ -4045,7 +4184,7 @@
#endif /* CONFIG_P2P */
if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
- wpa_s->current_ssid)
+ old_ssid)
params.prev_bssid = prev_bssid;
#ifdef CONFIG_SAE
@@ -4115,15 +4254,13 @@
}
#endif /* CONFIG_WEP */
- if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
+ if (old_ssid && old_ssid != ssid) {
/*
* Do not allow EAP session resumption between different
* network configurations.
*/
eapol_sm_invalidate_cached_session(wpa_s->eapol);
}
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = ssid;
if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
wpa_s->current_bss = bss;
@@ -5034,6 +5171,7 @@
* @src_addr: Source address of the EAPOL frame
* @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
* @len: Length of the EAPOL data
+ * @encrypted: Whether the frame was encrypted
*
* This function is called for each received EAPOL frame. Most driver
* interfaces rely on more generic OS mechanism for receiving frames through
@@ -5042,11 +5180,13 @@
* code by calling this function.
*/
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
- const u8 *buf, size_t len)
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " (encrypted=%d)",
+ MAC2STR(src_addr), encrypted);
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
if (wpa_s->own_disconnect_req) {
@@ -5092,6 +5232,7 @@
os_get_reltime(&wpa_s->pending_eapol_rx_time);
os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
ETH_ALEN);
+ wpa_s->pending_eapol_encrypted = encrypted;
}
return;
}
@@ -5101,7 +5242,8 @@
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
- wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
+ wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len,
+ encrypted);
return;
}
#endif /* CONFIG_AP */
@@ -5161,7 +5303,8 @@
#ifdef CONFIG_IBSS_RSN
if (wpa_s->current_ssid &&
wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
- ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
+ ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len,
+ encrypted);
return;
}
#endif /* CONFIG_IBSS_RSN */
@@ -5176,11 +5319,12 @@
if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
- eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+ eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len,
+ encrypted) > 0)
return;
wpa_drv_poll(wpa_s);
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
- wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+ wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len, encrypted);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
* Set portValid = true here since we are going to skip 4-way
@@ -5193,6 +5337,14 @@
}
+static void wpa_supplicant_rx_eapol_cb(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ wpa_supplicant_rx_eapol(ctx, src_addr, buf, len,
+ FRAME_ENCRYPTION_UNKNOWN);
+}
+
+
static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s)
{
return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) ||
@@ -5210,7 +5362,7 @@
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
wpas_eapol_needs_l2_packet(wpa_s) ?
- wpa_supplicant_rx_eapol : NULL,
+ wpa_supplicant_rx_eapol_cb : NULL,
wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
@@ -5264,7 +5416,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
" (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
- len - sizeof(*eth));
+ len - sizeof(*eth), FRAME_ENCRYPTION_UNKNOWN);
}
@@ -5990,6 +6142,7 @@
void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
struct fst_wpa_obj *iface_obj)
{
+ os_memset(iface_obj, 0, sizeof(*iface_obj));
iface_obj->ctx = wpa_s;
iface_obj->get_bssid = wpas_fst_get_bssid_cb;
iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
@@ -6781,6 +6934,7 @@
wpa_s->num_multichan_concurrent =
capa.num_multichan_concurrent;
wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+ wpa_s->max_num_akms = capa.max_num_akms;
if (capa.mac_addr_rand_scan_supported)
wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
@@ -6795,6 +6949,9 @@
wpa_s->extended_capa[2] & 0x40)
wpa_s->multi_bss_support = 1;
}
+#ifdef CONFIG_PASN
+ wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2);
+#endif /* CONFIG_PASN */
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -8070,6 +8227,26 @@
!ssid->mem_only_psk)
return 1;
+#ifdef IEEE8021X_EAPOL
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (ssid->eap.imsi_privacy_cert) {
+ struct crypto_rsa_key *key;
+ bool failed = false;
+
+ key = crypto_rsa_key_read(ssid->eap.imsi_privacy_cert, false);
+ if (!key)
+ failed = true;
+ crypto_rsa_key_free(key);
+ if (failed) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid imsi_privacy_cert (%s) - disable network",
+ ssid->eap.imsi_privacy_cert);
+ return 1;
+ }
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+#endif /* IEEE8021X_EAPOL */
+
return 0;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index fd54fef..8262eef 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1493,6 +1493,12 @@
# 2: do not allow PFS to be used
#dpp_pfs=0
+# DPP Network introduction type
+# 0: unprotected variant from DPP R1 (default)
+# 1: privacy protecting (station Connector encrypted) variant from
+# DPP R3
+#dpp_connector_privacy=0
+
# Whether beacon protection is enabled
# This depends on management frame protection (ieee80211w) being enabled and
# beacon protection support indication from the driver.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3adb819..faec32b 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -311,7 +311,6 @@
unsigned int p2p_24ghz_social_channels:1;
unsigned int pending_p2ps_group:1;
unsigned int pending_group_iface_for_p2ps:1;
- unsigned int p2p_go_found_external_scan:1;
unsigned int pending_p2ps_group_freq;
#ifdef CONFIG_WIFI_DISPLAY
@@ -556,12 +555,14 @@
int akmp;
int cipher;
u16 group;
+ bool secure_ltf;
int freq;
size_t kdk_len;
u8 trans_seq;
u8 status;
+ u8 own_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
size_t pmk_len;
u8 pmk[PMK_LEN_MAX];
@@ -608,7 +609,6 @@
u16 dst_port;
u8 dscp;
u8 protocol;
- u8 param_mask;
};
@@ -620,7 +620,6 @@
u8 dscp;
u8 next_header;
u8 flow_label[3];
- u8 param_mask;
};
@@ -757,6 +756,14 @@
struct wpa_bss *current_bss;
int ap_ies_from_associnfo;
unsigned int assoc_freq;
+ u8 ap_mld_addr[ETH_ALEN];
+ u8 valid_links; /* bitmap of valid MLO link IDs */
+ struct {
+ u8 addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ unsigned int freq;
+ struct wpa_bss *bss;
+ } links[MAX_NUM_MLD_LINKS];
u8 *last_con_fail_realm;
size_t last_con_fail_realm_len;
@@ -767,6 +774,11 @@
int key_mgmt;
int wpa_proto;
int mgmt_group_cipher;
+ /*
+ * Allowed key management suites for roaming/initial connection
+ * when the driver's SME is in use.
+ */
+ int allowed_key_mgmts;
void *drv_priv; /* private data used by driver_ops */
void *global_drv_priv;
@@ -902,6 +914,7 @@
unsigned int own_scan_requested:1;
unsigned int own_scan_running:1;
unsigned int clear_driver_scan_cache:1;
+ unsigned int manual_non_coloc_6ghz:1;
unsigned int manual_scan_id;
int scan_interval; /* time in sec between scans to find suitable AP */
int normal_scans; /* normal scans run before sched_scan */
@@ -951,6 +964,7 @@
unsigned int max_match_sets;
unsigned int max_remain_on_chan;
unsigned int max_stations;
+ unsigned int max_num_akms;
int pending_mic_error_report;
int pending_mic_error_pairwise;
@@ -966,6 +980,7 @@
struct wpabuf *pending_eapol_rx;
struct os_reltime pending_eapol_rx_time;
u8 pending_eapol_rx_src[ETH_ALEN];
+ enum frame_encryption pending_eapol_encrypted;
unsigned int last_eapol_matches_bssid:1;
unsigned int eapol_failed:1;
unsigned int eap_expected_failure:1;
@@ -1036,6 +1051,7 @@
unsigned int sae_pmksa_caching:1;
u16 seq_num;
u8 ext_auth_bssid[ETH_ALEN];
+ struct wpa_ssid *ext_auth_wpa_ssid;
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
int *sae_rejected_groups;
@@ -1160,6 +1176,7 @@
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
unsigned int group_formation_reported:1;
+ unsigned int p2p_go_no_pri_sec_switch:1;
unsigned int waiting_presence_resp;
int p2p_first_connection_timeout;
unsigned int p2p_nfc_tag_enabled:1;
@@ -1484,9 +1501,11 @@
int dpp_gas_dialog_token;
u8 dpp_intro_bssid[ETH_ALEN];
void *dpp_intro_network;
+ u8 dpp_intro_peer_version;
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
+ size_t dpp_pkex_code_len;
char *dpp_pkex_identifier;
enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
@@ -1517,11 +1536,33 @@
int dpp_reconfig_ssid_id;
struct dpp_reconfig_id *dpp_reconfig_id;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ struct os_reltime dpp_pb_time;
+ bool dpp_pb_configurator;
+ int *dpp_pb_freqs;
+ unsigned int dpp_pb_freq_idx;
+ unsigned int dpp_pb_announce_count;
+ struct wpabuf *dpp_pb_announcement;
+ struct dpp_bootstrap_info *dpp_pb_bi;
+ unsigned int dpp_pb_resp_freq;
+ u8 dpp_pb_init_hash[SHA256_MAC_LEN];
+ int dpp_pb_stop_iter;
+ bool dpp_pb_discovery_done;
+ u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN];
+ size_t dpp_pb_c_nonce_len;
+ bool dpp_pb_result_indicated;
+ struct os_reltime dpp_pb_announce_time;
+ struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT];
+ u8 dpp_pb_resp_hash[SHA256_MAC_LEN];
+ struct os_reltime dpp_pb_last_resp;
+ char *dpp_pb_cmd;
+#endif /* CONFIG_DPP3 */
#ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override;
char *dpp_discovery_override;
char *dpp_groups_override;
unsigned int dpp_ignore_netaccesskey_mismatch:1;
+ unsigned int dpp_discard_public_action:1;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_DPP */
@@ -1541,6 +1582,8 @@
#ifdef CONFIG_PASN
struct wpas_pasn pasn;
struct wpa_radio_work *pasn_auth_work;
+ unsigned int pasn_count;
+ struct pasn_auth *pasn_params;
#endif /* CONFIG_PASN */
struct scs_robust_av_data scs_robust_av_req;
u8 scs_dialog_token;
@@ -1652,8 +1695,9 @@
int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_terminate_proc(struct wpa_global *global);
-void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
- const u8 *buf, size_t len);
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *own_addr,
+ const u8 *buf, size_t len,
+ enum frame_encryption encrypted);
void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -1838,6 +1882,7 @@
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
+void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid);
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
@@ -1890,7 +1935,7 @@
int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
enum wpa_driver_if_type if_type,
unsigned int *num,
- unsigned int *freq_list);
+ struct weighted_pcl *freq_list);
int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
@@ -1923,7 +1968,7 @@
int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name,
size_t domain_name_length);
-int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
+int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *own_addr,
const u8 *bssid, int akmp, int cipher,
u16 group, int network_id,
const u8 *comeback, size_t comeback_len);
@@ -1934,6 +1979,10 @@
const struct ieee80211_mgmt *mgmt, size_t len);
int disabled_freq(struct wpa_supplicant *wpa_s, int freq);
-int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr,
+ const u8 *bssid);
+void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s,
+ struct pasn_auth *pasn_auth);
+void wpas_pasn_auth_work_done(struct wpa_supplicant *wpa_s, int status);
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index 7a558f3..a1846b1 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -7,3 +7,4 @@
p2p_add_cli_chan=1
oce=1
sae_pwe=2
+p2p_optimize_listen_chan=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index c2bd45f..e13ea8f 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -286,7 +286,7 @@
{
struct wpa_supplicant *wpa_s = ctx;
int res, pmk_len;
- u8 pmk[PMK_LEN];
+ u8 pmk[PMK_LEN_MAX];
wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s",
result_str(result));
@@ -336,7 +336,11 @@
wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
"handshake");
- pmk_len = PMK_LEN;
+ if (wpa_key_mgmt_sha384(wpa_s->key_mgmt))
+ pmk_len = PMK_LEN_SUITE_B_192;
+ else
+ pmk_len = PMK_LEN;
+
if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
#ifdef CONFIG_IEEE80211R
u8 buf[2 * PMK_LEN];
@@ -351,7 +355,7 @@
res = -1;
#endif /* CONFIG_IEEE80211R */
} else {
- res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+ res = eapol_sm_get_key(eapol, pmk, pmk_len);
if (res) {
/*
* EAP-LEAP is an exception from other EAP methods: it
@@ -1183,6 +1187,16 @@
wpas_notify_open_ssl_failure(wpa_s, reason_string);
}
+
+static bool wpas_encryption_required(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_s->wpa &&
+ wpa_sm_has_ptk_installed(wpa_s->wpa) &&
+ wpa_sm_pmf_enabled(wpa_s->wpa);
+}
+
#endif /* IEEE8021X_EAPOL */
@@ -1231,6 +1245,7 @@
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->eap_method_selected_cb = wpa_supplicant_eap_method_selected_cb;
ctx->open_ssl_failure_cb = wpa_supplicant_open_ssl_failure_cb;
+ ctx->encryption_required = wpas_encryption_required;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
@@ -1328,7 +1343,7 @@
#ifdef CONFIG_SAE
if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) &&
wpa_key_mgmt_sae(wpa_s->key_mgmt) &&
- (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
(ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
(ssid->group_cipher & WPA_CIPHER_TKIP))) {
wpa_printf(MSG_DEBUG,
@@ -1343,7 +1358,7 @@
wpa_s->sme.sae.state == SAE_ACCEPTED &&
wpa_s->sme.sae.pk &&
#endif /* CONFIG_SME */
- (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
(ssid->sae_pk != SAE_PK_MODE_ONLY ||
ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED ||
(ssid->group_cipher & WPA_CIPHER_TKIP))) {
@@ -1403,12 +1418,28 @@
{
struct wpa_supplicant *wpa_s = ctx;
- ptksa_cache_add(wpa_s->ptksa, addr, cipher, life_time, ptk);
+ ptksa_cache_add(wpa_s->ptksa, wpa_s->own_addr, addr, cipher, life_time,
+ ptk, NULL, NULL);
}
#endif /* CONFIG_NO_WPA */
+#ifdef CONFIG_PASN
+static int wpa_supplicant_set_ltf_keyseed(void *_wpa_s, const u8 *own_addr,
+ const u8 *peer_addr,
+ size_t ltf_keyseed_len,
+ const u8 *ltf_keyseed)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+
+ return wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, 0, 0,
+ NULL, ltf_keyseed_len,
+ ltf_keyseed, 0);
+}
+#endif /* CONFIG_PASN */
+
+
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
@@ -1471,6 +1502,9 @@
ctx->channel_info = wpa_supplicant_channel_info;
ctx->transition_disable = wpa_supplicant_transition_disable;
ctx->store_ptk = wpa_supplicant_store_ptk;
+#ifdef CONFIG_PASN
+ ctx->set_ltf_keyseed = wpa_supplicant_set_ltf_keyseed;
+#endif /* CONFIG_PASN */
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {