[wpa_supplicant] cumilative patch from commit bb945b98f
Bug: 275651698
Test: Connect to open, WPA2, WPA3 and passpoint network
Test: Establish P2P connection
Test: Basic SoftAp tests
Test: Regression test (b/275948027)
BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from opne source
bb945b98f Add 40 and 80 MHz channels 165 and 173 for 5 GHz IBSS/mesh
0059fa5ba 6 GHz: Fix secondary channel setting
744295c8b Add 6 GHz channel validation during channel switching
5349a45d3 Set interface state as inactive if mesh bringup fails
a4af79624 Handle signal termination in hostapd_cli for all cases
cf8f13ac8 Add support to send 320 MHz bandwidth through vendor subcmd
a0403c023 EHT: Validate the puncturing bitmap for ACS
af0f60e7d EHT: Calculate puncturing bitmap for ACS
f3206fbe9 EHT: Configuration option for ACS puncturing threshold
e3621867c EHT: Process puncturing bitmap from channel switch event
e277e577c nl80211: Send EHT puncturing bitmap to the driver for switch command
29a882bed EHT: Configure puncturing bitmap during channel switch
4942b19ff EHT: Send puncturing bitmap to the driver for AP bring up
f9fc2eabb EHT: Add puncturing bitmap to EHT Operation element
46a5d989d EHT: Downgrade bandwidths for VHT and HE when using puncturing
7618269ec EHT: Validate puncturing bitmap
9102fda31 EHT: Add configuration option for puncturing in AP mode
9e79439fc nl80211: Retrieve driver support for EHT puncturing
507be376c Sync with wireless-next.git include/uapi/linux/nl80211.h
591256a8c FILS: 320 MHz support in FD frame
903e3a1e6 FILS: Fix maximum NSS calculation for FD frame
ecae45ff6 FILS: Make HE a requirement for FILS discovery
4e86692ff AP: Fix 6 GHz AP setup after disable-enable
a34b8477a ml80211: Put wiphy idx to obtain correct country code
1491fc64a Define QCA vendor per-enum 64-bit pad attributes
55e31699e qca-vendor: Add QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL
b1f85957c Add QCA vendor commands to set and get MLO links state information
44b32a752 mesh: Add EHT support
c4cb62ca8 WPA_AUTH: MLO: Add functions to get the AA and SPA
cab963e9f AP: Split check_assoc_ies()
7a7a2256c common: Support parsing link specific association request
b39e35693 common: Add support for clearing elements
0b2fc4268 common: Split ieee8021_parse_elems()
df6561ec0 nl80211: AP MLD support for adding multi link stations
b8b4ceb8d nl80211: Properly stop and deinit MLO AP
2f8fc46ed nl80211: Provide link_id in EAPOL_RX and RX_MGMT events
821374d43 nl80211: Introduce and implement a callback to add an MLO link for AP MLD
47269be36 nl80211: Refactor i802_bss to support multiple links
eb146ee80 AP: Add some bridge port attribute settings
f628e6b30 nl80211: Make sure scan frequency debug buffer is NUL terminated
41d23254b nl80211: Fix frequencies array boundary check for scanned frequencies
a9012070a Android: Add wowlan_disconnect_on_deinit to template configuration
e2ea0fd70 EST: Write the RSA private key using the standard PRIVATE KEY format
bfd236df2 webkit2: Avoid deprecated function call
2c3202682 P2P: Filter out 6 GHz frequencies if not allowed for P2P connection
b2bf7e39e Update PMK in wpa_sm when roam+auth event indicated with authorized flag
6b9c86466 nl80211: Replace the channel flags for VHT support
6f63aca7b DPP: Allow both STA and AP configObject to be set
7292e30b7 DPP: Fix @CONF-OBJ-SEP@ parsing for multiple configs
c31600ce1 P2P: Allow GO BSSID to be specified for P2P_GROUP_ADD commands
0430756e6 P2P: Optimize join scan frequency
b3921db42 nl80211: Add frequency info in start AP command
40c139664 macsec_linux: Add support for MACsec hardware offload
6d24673ab mka: Allow configuration of MACsec hardware offload
3081a9cb6 hostapd: Output country_code and country3 when using STATUS
91ad7a309 FT: Store PTKSA entry for the correct BSSID in the FT protocol case
3f3e356fa Mark addr argument to storing PTKSA const
242c3ad99 FT: Store PTKSA from FT protocol
ba6954874 Mark wpa_auth_remove_ptksa() static
3b1ad1334 FT: Include KDK in FT specific PTK derivation on the AP
870a5bdc0 nl80211: Report guard interval and dual carrier modulation
edcad193a dbus: Add inactive time to D-Bus signal info
a678a510f dbus: Add D-Bus signal for PSK mismatch heuristics
691f729d5 P2P: Make invitation flow less aggressive
f4a7e2a07 Rework IBSS/mesh 80 MHz channel selection
f91f971bd Fix creating 6 GHz IBSS/mesh on 5/6 GHz-capable PHYs
c623cee42 Make arrays static const in ibss_mesh_select_*()
64043e615 Split ibss_mesh_setup_freq() into multiple functions
8085a7e65 wpa_supplicant: Add option to explicitly set 4addr mode
1ffc7d1c6 Apply bias towards 6 GHz in roaming
faa410292 WNM: Event report handling for BSS color collision and in-use
97405be96 Small textual improvements to wpa_supplicant man page
ec02a0e93 hostapd: Output hw_mode when using STATUS
390e24c6c EAP-TTLS server: Add Ident field to MS-CHAP-Error
4ae798a22 P2P: Pick the best driver pref freq for invitation process
6c75f1dfa Send broadcast Probe Response frames on the 6 GHz band
edfcb2f1a MLD STA: Indicate MLO support in NL80211_CMD_CONNECT
c91852044 MLD STA: Add support for SAE external authentication offload to userspace
575712450 qca-vendor: Add QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY
ba150059d FT: Store PMK-R0/PMK-R1 after EAPOL-Key msg 2/4 MIC validation
56662f36d Refine vendor subcmd QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS
72b8193f4 MACsec: Remove EAP Session-Id length constraint
3915e8834 hostapd: Report error on unknown ACCEPT_ACL/DENY_ACL commands
2cff340d1 utils: Move log2pcap to python3
12de8112b Fix BSS age underflow
d31c2b43a Fix segfault in case of an invalid configuration
a32b424a3 MLD STA: Use AP MLD address in PMKSA cache attempts for driver-SME case
8c4790cef MLD STA: Store PMKSA with AP MLD address for MLO connection event
bf124a03d SAE: Update PT value at later point for SME cases, if needed
1aadcca0a P2P: Enable SAE-H2E for client when joining a 6 GHz group
37f8257c4 SAE: Extend automatic enabling of H2E on 6 GHz to additional cases
89377c6b9 OCV: Fix build without CONFIG_OCV=y
2e47ea22c P2P: Fix handling Service Discovery Response received by GO device
dc7e330e0 Set OCV capability based on Association Request frame RSNE
831be6514 WPS: Do not indicate incorrect PBC overlap based on partner link
c9fc12425 P2P: Make wpas_p2p_notif_pbc_overlap() static
Change-Id: I1eb61fc82b98b937a2ff37a30e60e28129fe143d
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 8cb5813..1181c7d 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -326,6 +326,7 @@
dl_list_init(&chan->survey_list);
chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED;
chan->min_nf = 0;
+ chan->punct_bitmap = 0;
}
}
@@ -711,6 +712,62 @@
#define ACS_24GHZ_PREFER_1_6_11 0.8
#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
+#ifdef CONFIG_IEEE80211BE
+static void acs_update_puncturing_bitmap(struct hostapd_iface *iface,
+ struct hostapd_hw_modes *mode, u32 bw,
+ int n_chans,
+ struct hostapd_channel_data *chan,
+ long double factor,
+ int index_primary)
+{
+ struct hostapd_config *conf = iface->conf;
+ struct hostapd_channel_data *adj_chan = NULL, *first_chan = chan;
+ int i;
+ long double threshold;
+
+ /*
+ * If threshold is 0 or user configured puncturing pattern is
+ * available then don't add additional puncturing.
+ */
+ if (!conf->punct_acs_threshold || conf->punct_bitmap)
+ return;
+
+ if (is_24ghz_mode(mode->mode) || bw < 80)
+ return;
+
+ threshold = factor * conf->punct_acs_threshold / 100;
+ for (i = 0; i < n_chans; i++) {
+ int adj_freq;
+
+ if (i == index_primary)
+ continue; /* Cannot puncture primary channel */
+
+ if (i > index_primary)
+ adj_freq = chan->freq + (i - index_primary) * 20;
+ else
+ adj_freq = chan->freq - (index_primary - i) * 20;
+
+ adj_chan = acs_find_chan(iface, adj_freq);
+ if (!adj_chan) {
+ chan->punct_bitmap = 0;
+ return;
+ }
+
+ if (i == 0)
+ first_chan = adj_chan;
+
+ if (adj_chan->interference_factor > threshold)
+ chan->punct_bitmap |= BIT(i);
+ }
+
+ if (!is_punct_bitmap_valid(bw, (chan->freq - first_chan->freq) / 20,
+ chan->punct_bitmap))
+ chan->punct_bitmap = 0;
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
static void
acs_find_ideal_chan_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode,
@@ -734,7 +791,13 @@
/* Since in the current ACS implementation the first channel is
* always a primary channel, skip channels not available as
* primary until more sophisticated channel selection is
- * implemented. */
+ * implemented.
+ *
+ * If this implementation is changed to allow any channel in
+ * the bandwidth to be the primary one, the last parameter to
+ * acs_update_puncturing_bitmap() should be changed to the index
+ * of the primary channel
+ */
if (!chan_pri_allowed(chan))
continue;
@@ -913,8 +976,20 @@
if (acs_usable_chan(chan) &&
(!*ideal_chan || factor < *ideal_factor)) {
+ /* Reset puncturing bitmap for the previous ideal
+ * channel */
+ if (*ideal_chan)
+ (*ideal_chan)->punct_bitmap = 0;
+
*ideal_factor = factor;
*ideal_chan = chan;
+
+#ifdef CONFIG_IEEE80211BE
+ if (iface->conf->ieee80211be)
+ acs_update_puncturing_bitmap(iface, mode, bw,
+ n_chans, chan,
+ factor, 0);
+#endif /* CONFIG_IEEE80211BE */
}
/* This channel would at least be usable */
@@ -991,9 +1066,22 @@
if (ideal_chan) {
wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
ideal_chan->chan, ideal_chan->freq, ideal_factor);
+
+#ifdef CONFIG_IEEE80211BE
+ if (iface->conf->punct_acs_threshold)
+ wpa_printf(MSG_DEBUG, "ACS: RU puncturing bitmap 0x%x",
+ ideal_chan->punct_bitmap);
+#endif /* CONFIG_IEEE80211BE */
+
return ideal_chan;
}
+#ifdef CONFIG_IEEE80211BE
+ if (iface->conf->punct_acs_threshold)
+ wpa_printf(MSG_DEBUG, "ACS: RU puncturing bitmap 0x%x",
+ ideal_chan->punct_bitmap);
+#endif /* CONFIG_IEEE80211BE */
+
return rand_chan;
}
@@ -1106,6 +1194,9 @@
iface->conf->channel = ideal_chan->chan;
iface->freq = ideal_chan->freq;
+#ifdef CONFIG_IEEE80211BE
+ iface->conf->punct_bitmap = ideal_chan->punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
acs_adjust_secondary(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 5dc8a8f..b5fcc38 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1447,6 +1447,13 @@
#ifdef CONFIG_FILS
if (full_config && bss->fils_discovery_max_int &&
+ (!conf->ieee80211ax || bss->disable_11ax)) {
+ wpa_printf(MSG_ERROR,
+ "Currently IEEE 802.11ax support is mandatory to enable FILS discovery transmission.");
+ return -1;
+ }
+
+ if (full_config && bss->fils_discovery_max_int &&
bss->unsol_bcast_probe_resp_interval) {
wpa_printf(MSG_ERROR,
"Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time");
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 6dbb223..07ee31c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -284,6 +284,7 @@
char bridge[IFNAMSIZ + 1];
char vlan_bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
+ int bridge_hairpin; /* hairpin_mode on bridge members */
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
@@ -748,6 +749,7 @@
#endif /* CONFIG_FILS */
int multicast_to_unicast;
+ int bridge_multicast_to_unicast;
int broadcast_deauth;
@@ -845,6 +847,19 @@
u32 macsec_replay_window;
/**
+ * macsec_offload - Enable MACsec offload
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0 = MACSEC_OFFLOAD_OFF (default)
+ * 1 = MACSEC_OFFLOAD_PHY
+ * 2 = MACSEC_OFFLOAD_MAC
+ */
+ int macsec_offload;
+
+ /**
* macsec_port - MACsec port (in SCI)
*
* Port component of the SCI.
@@ -1143,6 +1158,8 @@
enum oper_chan_width eht_oper_chwidth;
u8 eht_oper_centr_freq_seg0_idx;
struct eht_phy_capabilities_info eht_phy_capab;
+ u16 punct_bitmap; /* a bitmap of disabled 20 MHz channels */
+ u8 punct_acs_threshold;
#endif /* CONFIG_IEEE80211BE */
/* EHT enable/disable config from CHAN_SWITCH */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 1ffc37f..f77f738 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -459,6 +459,7 @@
params.qosinfo = qosinfo;
params.support_p2p_ps = supp_p2p_ps;
params.set = set;
+ params.mld_link_id = -1;
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index dbc6b06..c25a5bb 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -533,8 +533,7 @@
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
const struct ieee80211_mgmt *req,
int is_p2p, size_t *resp_len,
- bool bcast_probe_resp, const u8 *known_bss,
- u8 known_bss_len)
+ const u8 *known_bss, u8 known_bss_len)
{
struct ieee80211_mgmt *resp;
u8 *pos, *epos, *csa_pos;
@@ -585,6 +584,8 @@
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
buflen += 3 + sizeof(struct ieee80211_eht_operation);
+ if (hapd->iconf->punct_bitmap)
+ buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
}
#endif /* CONFIG_IEEE80211BE */
@@ -603,9 +604,16 @@
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_PROBE_RESP);
- if (req)
+ /* Unicast the response to all requests on bands other than 6 GHz. For
+ * the 6 GHz, unicast is used only if the actual SSID is not included in
+ * the Beacon frames. Otherwise, broadcast response is used per IEEE
+ * Std 802.11ax-2021, 26.17.2.3.2. Broadcast address is also used for
+ * the Probe Response frame template for the unsolicited (i.e., not as
+ * a response to a specific request) case. */
+ if (req && (!is_6ghz_op_class(hapd->iconf->op_class) ||
+ hapd->conf->ignore_broadcast_ssid))
os_memcpy(resp->da, req->sa, ETH_ALEN);
- else if (bcast_probe_resp)
+ else
os_memset(resp->da, 0xff, ETH_ALEN);
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
@@ -1230,7 +1238,7 @@
" signal=%d", MAC2STR(mgmt->sa), ssi_signal);
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
- &resp_len, false, elems.mbssid_known_bss,
+ &resp_len, elems.mbssid_known_bss,
elems.mbssid_known_bss_len);
if (resp == NULL)
return;
@@ -1301,7 +1309,7 @@
"this");
/* Generate a Probe Response template for the non-P2P case */
- return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false, NULL, 0);
+ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, NULL, 0);
}
#endif /* NEED_AP_MLME */
@@ -1320,7 +1328,7 @@
return hostapd_gen_probe_resp(hapd, NULL, 0,
¶ms->unsol_bcast_probe_resp_tmpl_len,
- true, NULL, 0);
+ NULL, 0);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1351,6 +1359,9 @@
phy_index = FD_CAP_PHY_INDEX_HE;
switch (hapd->iconf->op_class) {
+ case 137:
+ chwidth = FD_CAP_BSS_CHWIDTH_320;
+ break;
case 135:
mcs_nss_size += 4;
/* fallthrough */
@@ -1404,14 +1415,37 @@
cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
- if (mode) {
- u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
+ if (mode && phy_index == FD_CAP_PHY_INDEX_HE) {
+ const u8 *he_mcs = mode->he_capab[IEEE80211_MODE_AP].mcs;
int i;
- u16 nss = 0;
+ u16 nss = 0, mcs[6];
+
+ os_memset(mcs, 0xffff, 6 * sizeof(u16));
+
+ if (mcs_nss_size == 4) {
+ mcs[0] = WPA_GET_LE16(&he_mcs[0]);
+ mcs[1] = WPA_GET_LE16(&he_mcs[2]);
+ }
+
+ if (mcs_nss_size == 8) {
+ mcs[2] = WPA_GET_LE16(&he_mcs[4]);
+ mcs[3] = WPA_GET_LE16(&he_mcs[6]);
+ }
+
+ if (mcs_nss_size == 12) {
+ mcs[4] = WPA_GET_LE16(&he_mcs[8]);
+ mcs[5] = WPA_GET_LE16(&he_mcs[10]);
+ }
for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
u16 nss_mask = 0x3 << (i * 2);
+ /*
+ * If NSS values supported by RX and TX are different
+ * then choose the smaller of the two as the maximum
+ * supported NSS as that is the value supported by
+ * both RX and TX.
+ */
if (mcs_nss_size == 4 &&
(((mcs[0] & nss_mask) == nss_mask) ||
((mcs[1] & nss_mask) == nss_mask)))
@@ -1655,6 +1689,8 @@
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
tail_len += 3 + sizeof(struct ieee80211_eht_operation);
+ if (hapd->iconf->punct_bitmap)
+ tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
}
#endif /* CONFIG_IEEE80211BE */
@@ -2065,6 +2101,10 @@
params.fd_frame_tmpl = hostapd_fils_discovery(hapd, ¶ms);
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211BE
+ params.punct_bitmap = iconf->punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
+
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
iconf->channel, iconf->enable_edmg,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 168e5f5..6934a73 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -212,6 +212,26 @@
}
+static const char * hw_mode_str(enum hostapd_hw_mode mode)
+{
+ switch (mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return "b";
+ case HOSTAPD_MODE_IEEE80211G:
+ return "g";
+ case HOSTAPD_MODE_IEEE80211A:
+ return "a";
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "ad";
+ case HOSTAPD_MODE_IEEE80211ANY:
+ return "any";
+ case NUM_HOSTAPD_MODES:
+ return "invalid";
+ }
+ return "unknown";
+}
+
+
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
@@ -696,6 +716,7 @@
{
struct hostapd_iface *iface = hapd->iface;
struct hostapd_hw_modes *mode = iface->current_mode;
+ struct hostapd_config *iconf = hapd->iconf;
int len = 0, ret, j;
size_t i;
@@ -730,6 +751,24 @@
return len;
len += ret;
+ if (mode) {
+ ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n",
+ hw_mode_str(mode->mode));
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
+ if (iconf->country[0] && iconf->country[1]) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "country_code=%c%c\ncountry3=0x%X\n",
+ iconf->country[0], iconf->country[1],
+ iconf->country[2]);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
if (!iface->cac_started || !iface->dfs_cac_ms) {
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%d\n"
@@ -941,16 +980,27 @@
} \
} while (0)
+#define SET_CSA_SETTING_EXT(str) \
+ do { \
+ const char *pos2 = os_strstr(pos, " " #str "="); \
+ if (pos2) { \
+ pos2 += sizeof(" " #str "=") - 1; \
+ settings->str = atoi(pos2); \
+ } \
+ } while (0)
+
SET_CSA_SETTING(center_freq1);
SET_CSA_SETTING(center_freq2);
SET_CSA_SETTING(bandwidth);
SET_CSA_SETTING(sec_channel_offset);
+ SET_CSA_SETTING_EXT(punct_bitmap);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->freq_params.he_enabled = !!os_strstr(pos, " he");
settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
+#undef SET_CSA_SETTING_EXT
return 0;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 4c33e86..8fc128e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -859,7 +859,7 @@
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
- int finished)
+ u16 punct_bitmap, int finished)
{
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs0, is_dfs;
@@ -868,14 +868,14 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver %s channel switch: iface->freq=%d, freq=%d, ht=%d, vht_ch=0x%x, "
- "he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: iface->freq=%d, freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d, puncturing_bitmap=0x%x",
finished ? "had" : "starting",
hapd->iface->freq,
freq, ht, hapd->iconf->ch_switch_vht_config,
hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_eht_config, offset,
- width, channel_width_to_string(width), cf1, cf2);
+ width, channel_width_to_string(width), cf1, cf2,
+ punct_bitmap);
if (!hapd->iface->current_mode) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
@@ -987,6 +987,9 @@
hostapd_set_oper_chwidth(hapd->iconf, chwidth);
hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
+#ifdef CONFIG_IEEE80211BE
+ hapd->iconf->punct_bitmap = punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
if (hapd->iconf->ieee80211ac) {
hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
if (chwidth == CONF_OPER_CHWIDTH_160MHZ)
@@ -1001,11 +1004,11 @@
hapd->iface->num_hw_features);
wpa_msg(hapd->msg_ctx, MSG_INFO,
- "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d is_dfs0=%d dfs=%d",
+ "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d is_dfs0=%d dfs=%d puncturing_bitmap=0x%04x",
finished ? WPA_EVENT_CHANNEL_SWITCH :
WPA_EVENT_CHANNEL_SWITCH_STARTED,
freq, ht, offset, channel_width_to_string(width),
- cf1, cf2, is_dfs0, is_dfs);
+ cf1, cf2, is_dfs0, is_dfs, punct_bitmap);
if (!finished)
return;
@@ -2028,6 +2031,7 @@
data->ch_switch.ch_width,
data->ch_switch.cf1,
data->ch_switch.cf2,
+ data->ch_switch.punct_bitmap,
event == EVENT_CH_SWITCH);
break;
case EVENT_CONNECT_FAILED_REASON:
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 58492e5..8b3fb40 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1435,6 +1435,22 @@
return -1;
}
+ if (conf->bridge[0]) {
+ /* Set explicitly configured bridge parameters that might have
+ * been lost if the interface has been removed out of the
+ * bridge. */
+
+ /* multicast to unicast on bridge ports */
+ if (conf->bridge_multicast_to_unicast)
+ hostapd_drv_br_port_set_attr(
+ hapd, DRV_BR_PORT_ATTR_MCAST2UCAST, 1);
+
+ /* hairpin mode */
+ if (conf->bridge_hairpin)
+ hostapd_drv_br_port_set_attr(
+ hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 1);
+ }
+
if (conf->proxy_arp) {
if (x_snoop_init(hapd)) {
wpa_printf(MSG_ERROR,
@@ -1749,7 +1765,7 @@
bw = center_idx_to_bw_6ghz(seg0);
/* Assign the secondary channel if absent in config for
* bandwidths > 20 MHz */
- if (bw > 20 && !iface->conf->secondary_channel) {
+ if (bw > 0 && !iface->conf->secondary_channel) {
if (((iface->conf->channel - 1) / 4) % 2)
iface->conf->secondary_channel = -1;
else
@@ -1768,6 +1784,11 @@
} else {
int ret;
+ if (iface->conf->acs) {
+ iface->freq = 0;
+ iface->conf->channel = 0;
+ }
+
ret = configured_fixed_chan_to_freq(iface);
if (ret < 0)
goto fail;
@@ -3634,6 +3655,9 @@
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
+#ifdef CONFIG_IEEE80211BE
+ u16 old_punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
u8 chan, bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
@@ -3679,9 +3703,16 @@
if (ret)
return ret;
+#ifdef CONFIG_IEEE80211BE
+ old_punct_bitmap = iface->conf->punct_bitmap;
+ iface->conf->punct_bitmap = settings->punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
/* change back the configuration */
+#ifdef CONFIG_IEEE80211BE
+ iface->conf->punct_bitmap = old_punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
hostapd_change_config_freq(iface->bss[0], iface->conf,
&old_freq, NULL);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index a88f9b6..b81da30 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -727,7 +727,7 @@
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2,
- int finished);
+ u16 punct_bitmap, int finished);
struct survey_results;
void hostapd_event_get_survey(struct hostapd_iface *iface,
struct survey_results *survey_results);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index ed5ff41..842d9f5 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -893,6 +893,55 @@
}
+static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_config *conf = iface->conf;
+ u8 bw, start_chan;
+
+ if (!conf->punct_bitmap)
+ return true;
+
+ if (!conf->ieee80211be) {
+ wpa_printf(MSG_ERROR,
+ "Currently RU puncturing is supported only if ieee80211be is enabled");
+ return false;
+ }
+
+ if (iface->freq >= 2412 && iface->freq <= 2484) {
+ wpa_printf(MSG_ERROR,
+ "RU puncturing not supported in 2.4 GHz");
+ return false;
+ }
+
+ switch (conf->eht_oper_chwidth) {
+ case 0:
+ wpa_printf(MSG_ERROR,
+ "RU puncturing is supported only in 80 MHz and 160 MHz");
+ return false;
+ case 1:
+ bw = 80;
+ start_chan = conf->eht_oper_centr_freq_seg0_idx - 6;
+ break;
+ case 2:
+ bw = 160;
+ start_chan = conf->eht_oper_centr_freq_seg0_idx - 14;
+ break;
+ default:
+ return false;
+ }
+
+ if (!is_punct_bitmap_valid(bw, (conf->channel - start_chan) / 4,
+ conf->punct_bitmap)) {
+ wpa_printf(MSG_ERROR, "Invalid puncturing bitmap");
+ return false;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ return true;
+}
+
+
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_freq;
@@ -915,6 +964,9 @@
if (!hostapd_is_usable_edmg(iface))
return 0;
+ if (!hostapd_is_usable_punct_bitmap(iface))
+ return 0;
+
if (!iface->conf->secondary_channel)
return 1;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index e53f0dc..0142ee4 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -3652,40 +3652,34 @@
}
-static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ies, size_t ies_len, int reassoc)
+static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ies, size_t ies_len,
+ struct ieee802_11_elems *elems, int reassoc)
{
- struct ieee802_11_elems elems;
int resp;
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *p2p_dev_addr = NULL;
- if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "Station sent an invalid "
- "association request");
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
-
- resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
+ resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
+ resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
+ resp = check_ext_capab(hapd, sta, elems->ext_capab,
+ elems->ext_capab_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = copy_supp_rates(hapd, sta, &elems);
+ resp = copy_supp_rates(hapd, sta, elems);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
+ resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
+ resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
@@ -3698,11 +3692,11 @@
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac) {
- resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
+ resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
- resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
+ resp = set_sta_vht_opmode(hapd, sta, elems->vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
@@ -3715,9 +3709,9 @@
return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
}
- if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
- resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
- elems.vendor_vht_len);
+ if (hapd->conf->vendor_vht && !elems->vht_capabilities) {
+ resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht,
+ elems->vendor_vht_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
@@ -3725,8 +3719,8 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
- elems.he_capabilities,
- elems.he_capabilities_len);
+ elems->he_capabilities,
+ elems->he_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -3747,7 +3741,7 @@
return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED;
}
resp = copy_sta_he_6ghz_capab(hapd, sta,
- elems.he_6ghz_band_cap);
+ elems->he_6ghz_band_cap);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
@@ -3756,17 +3750,17 @@
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
- elems.he_capabilities,
- elems.he_capabilities_len,
- elems.eht_capabilities,
- elems.eht_capabilities_len);
+ elems->he_capabilities,
+ elems->he_capabilities_len,
+ elems->eht_capabilities,
+ elems->eht_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_P2P
- if (elems.p2p) {
+ if (elems->p2p && ies && ies_len) {
wpabuf_free(sta->p2p_ie);
sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
P2P_IE_VENDOR_TYPE);
@@ -3778,13 +3772,13 @@
}
#endif /* CONFIG_P2P */
- if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
- wpa_ie = elems.rsn_ie;
- wpa_ie_len = elems.rsn_ie_len;
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) {
+ wpa_ie = elems->rsn_ie;
+ wpa_ie_len = elems->rsn_ie_len;
} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
- elems.wpa_ie) {
- wpa_ie = elems.wpa_ie;
- wpa_ie_len = elems.wpa_ie_len;
+ elems->wpa_ie) {
+ wpa_ie = elems->wpa_ie;
+ wpa_ie_len = elems->wpa_ie_len;
} else {
wpa_ie = NULL;
wpa_ie_len = 0;
@@ -3792,7 +3786,7 @@
#ifdef CONFIG_WPS
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
- if (hapd->conf->wps_state && elems.wps_ie) {
+ if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) {
wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
"Request - assume WPS is used");
if (check_sa_query(hapd, sta, reassoc))
@@ -3846,10 +3840,12 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
- elems.rsnxe ? elems.rsnxe - 2 : NULL,
- elems.rsnxe ? elems.rsnxe_len + 2 : 0,
- elems.mdie, elems.mdie_len,
- elems.owe_dh, elems.owe_dh_len);
+ elems->rsnxe ? elems->rsnxe - 2 :
+ NULL,
+ elems->rsnxe ? elems->rsnxe_len + 2 :
+ 0,
+ elems->mdie, elems->mdie_len,
+ elems->owe_dh, elems->owe_dh_len);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -3906,7 +3902,7 @@
if (hapd->conf->sae_pwe == SAE_PWE_BOTH &&
sta->auth_alg == WLAN_AUTH_SAE &&
sta->sae && !sta->sae->h2e &&
- ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len,
WLAN_RSNX_CAPAB_SAE_H2E)) {
wpa_printf(MSG_INFO, "SAE: " MACSTR
" indicates support for SAE H2E, but did not use it",
@@ -3918,9 +3914,9 @@
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
- elems.owe_dh) {
- resp = owe_process_assoc_req(hapd, sta, elems.owe_dh,
- elems.owe_dh_len);
+ elems->owe_dh) {
+ resp = owe_process_assoc_req(hapd, sta, elems->owe_dh,
+ elems->owe_dh_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
@@ -3934,7 +3930,7 @@
(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
- elems.owe_dh) {
+ elems->owe_dh) {
sta->dpp_pfs = dpp_pfs_init(
wpabuf_head(hapd->conf->dpp_netaccesskey),
wpabuf_len(hapd->conf->dpp_netaccesskey));
@@ -3945,8 +3941,8 @@
goto pfs_fail;
}
- if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
- elems.owe_dh_len) < 0) {
+ if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh,
+ elems->owe_dh_len) < 0) {
dpp_pfs_free(sta->dpp_pfs);
sta->dpp_pfs = NULL;
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3969,7 +3965,7 @@
}
#ifdef CONFIG_HS20
} else if (hapd->conf->osen) {
- if (elems.osen == NULL) {
+ if (!elems->osen) {
hostapd_logger(
hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
@@ -3987,7 +3983,7 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
- elems.osen - 2, elems.osen_len + 2) < 0)
+ elems->osen - 2, elems->osen_len + 2) < 0)
return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
} else
@@ -3999,12 +3995,12 @@
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
- if (elems.hs20 && elems.hs20_len > 4) {
+ if (elems->hs20 && elems->hs20_len > 4) {
int release;
- sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
- elems.hs20_len - 4);
- release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
+ sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4,
+ elems->hs20_len - 4);
+ release = ((elems->hs20[4] >> 4) & 0x0f) + 1;
if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) &&
hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_printf(MSG_DEBUG,
@@ -4017,10 +4013,10 @@
}
wpabuf_free(sta->roaming_consortium);
- if (elems.roaming_cons_sel)
+ if (elems->roaming_cons_sel)
sta->roaming_consortium = wpabuf_alloc_copy(
- elems.roaming_cons_sel + 4,
- elems.roaming_cons_sel_len - 4);
+ elems->roaming_cons_sel + 4,
+ elems->roaming_cons_sel_len - 4);
else
sta->roaming_consortium = NULL;
#endif /* CONFIG_HS20 */
@@ -4028,16 +4024,16 @@
#ifdef CONFIG_FST
wpabuf_free(sta->mb_ies);
if (hapd->iface->fst)
- sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
+ sta->mb_ies = mb_ies_by_info(&elems->mb_ies);
else
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
#ifdef CONFIG_MBO
- mbo_ap_check_sta_assoc(hapd, sta, &elems);
+ mbo_ap_check_sta_assoc(hapd, sta, elems);
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
- elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
+ elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
wpa_printf(MSG_INFO,
"MBO: Reject WPA2 association without PMF");
@@ -4067,7 +4063,7 @@
&tx_seg1_idx) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ res = ocv_verify_tx_params(elems->oci, elems->oci_len, &ci,
tx_chanwidth, tx_seg1_idx);
if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
res == OCI_NOT_FOUND) {
@@ -4086,18 +4082,18 @@
}
#endif /* CONFIG_FILS && CONFIG_OCV */
- ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
- elems.supp_op_classes_len);
+ ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes,
+ elems->supp_op_classes_len);
if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
- elems.rrm_enabled &&
- elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
- os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ elems->rrm_enabled &&
+ elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled,
sizeof(sta->rrm_enabled_capa));
- if (elems.power_capab) {
- sta->min_tx_power = elems.power_capab[0];
- sta->max_tx_power = elems.power_capab[1];
+ if (elems->power_capab) {
+ sta->min_tx_power = elems->power_capab[0];
+ sta->max_tx_power = elems->power_capab[1];
sta->power_capab = 1;
} else {
sta->power_capab = 0;
@@ -4107,6 +4103,22 @@
}
+static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ies, size_t ies_len, int reassoc)
+{
+ struct ieee802_11_elems elems;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station sent an invalid association request");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc);
+}
+
+
static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
u16 reason_code)
{
@@ -4266,6 +4278,8 @@
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
buflen += 3 + sizeof(struct ieee80211_eht_operation);
+ if (hapd->iconf->punct_bitmap)
+ buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
}
#endif /* CONFIG_IEEE80211BE */
@@ -5330,10 +5344,10 @@
pos = &mgmt->u.action.u.public_action.action;
end = ((const u8 *) mgmt) + len;
- gas_query_ap_rx(hapd->gas, mgmt->sa,
- mgmt->u.action.category,
- pos, end - pos, freq);
- return 1;
+ if (gas_query_ap_rx(hapd->gas, mgmt->sa,
+ mgmt->u.action.category,
+ pos, end - pos, freq) == 0)
+ return 1;
}
#endif /* CONFIG_DPP */
if (hapd->public_action_cb) {
@@ -7015,4 +7029,73 @@
return eid;
}
+
+static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0)
+{
+ u8 first_chan = *seg0 - 6, sec_chan;
+
+ switch (bitmap) {
+ case 0x6:
+ *seg0 = 0;
+ return;
+ case 0x8:
+ case 0x4:
+ case 0x2:
+ case 0x1:
+ case 0xC:
+ case 0x3:
+ if (pri_chan < *seg0)
+ *seg0 -= 4;
+ else
+ *seg0 += 4;
+ break;
+ }
+
+ if (pri_chan < *seg0)
+ sec_chan = pri_chan + 4;
+ else
+ sec_chan = pri_chan - 4;
+
+ if (bitmap & BIT((sec_chan - first_chan) / 4))
+ *seg0 = 0;
+}
+
+
+static void punct_update_legacy_bw_160(u8 bitmap, u8 pri,
+ enum oper_chan_width *width, u8 *seg0)
+{
+ if (pri < *seg0) {
+ *seg0 -= 8;
+ if (bitmap & 0x0F) {
+ *width = 0;
+ punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
+ }
+ } else {
+ *seg0 += 8;
+ if (bitmap & 0xF0) {
+ *width = 0;
+ punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri,
+ seg0);
+ }
+ }
+}
+
+
+void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
+ u8 *seg0, u8 *seg1)
+{
+ if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) {
+ *width = CONF_OPER_CHWIDTH_USE_HT;
+ punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0);
+ }
+
+ if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) {
+ *width = CONF_OPER_CHWIDTH_80MHZ;
+ *seg1 = 0;
+ punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
+ }
+
+ /* TODO: 320 MHz */
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 5f443fc..1e4c843 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -18,6 +18,7 @@
struct ieee80211_mgmt;
struct radius_sta;
enum ieee80211_op_mode;
+enum oper_chan_width;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@@ -222,5 +223,7 @@
unsigned int frame_stype, u8 elem_count,
u8 **elem_offset,
const u8 *known_bss, size_t known_bss_len);
+void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
+ enum oper_chan_width *width, u8 *seg0, u8 *seg1);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index caaadce..6ebe0f9 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -202,6 +202,9 @@
if (!hapd->iface->current_mode)
return eid;
+ if (hapd->iconf->punct_bitmap)
+ elen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
+
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + elen;
*pos++ = WLAN_EID_EXT_EHT_OPERATION;
@@ -253,6 +256,12 @@
oper->oper_info.ccfs0 = seg0 ? seg0 : hapd->iconf->channel;
oper->oper_info.ccfs1 = seg1;
+ if (hapd->iconf->punct_bitmap) {
+ oper->oper_params |= EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT;
+ oper->oper_info.disabled_chan_bitmap =
+ host_to_le16(hapd->iconf->punct_bitmap);
+ }
+
return pos + elen;
}
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 12273c3..548a448 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -219,10 +219,20 @@
pos += 6; /* skip the fixed part */
if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ enum oper_chan_width oper_chwidth =
+ hostapd_get_oper_chwidth(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;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->punct_bitmap) {
+ punct_update_legacy_bw(hapd->iconf->punct_bitmap,
+ hapd->iconf->channel,
+ &oper_chwidth, &seg0, &seg1);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
if (!seg0)
seg0 = hapd->iconf->channel;
@@ -253,7 +263,7 @@
*pos++ = control;
/* Channel Center Freq Seg0/Seg1 */
- if (hapd->iconf->he_oper_chwidth == 2) {
+ if (oper_chwidth == 2) {
/*
* Seg 0 indicates the channel center frequency index of
* the 160 MHz channel.
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 681b6d7..db615a3 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -75,6 +75,10 @@
{
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
+ enum oper_chan_width oper_chwidth =
+ hostapd_get_oper_chwidth(hapd->iconf);
+ u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx;
if (is_6ghz_op_class(hapd->iconf->op_class))
return eid;
@@ -85,18 +89,24 @@
oper = (struct ieee80211_vht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->punct_bitmap) {
+ punct_update_legacy_bw(hapd->iconf->punct_bitmap,
+ hapd->iconf->channel,
+ &oper_chwidth, &seg0, &seg1);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
/*
* center freq = 5 GHz + (5 * index)
* So index 42 gives center freq 5.210 GHz
* which is channel 42 in 5G band
*/
- oper->vht_op_info_chan_center_freq_seg0_idx =
- hapd->iconf->vht_oper_centr_freq_seg0_idx;
- oper->vht_op_info_chan_center_freq_seg1_idx =
- hapd->iconf->vht_oper_centr_freq_seg1_idx;
+ oper->vht_op_info_chan_center_freq_seg0_idx = seg0;
+ oper->vht_op_info_chan_center_freq_seg1_idx = seg1;
- oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
- if (hapd->iconf->vht_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
+ oper->vht_op_info_chwidth = oper_chwidth;
+ if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
/*
* Convert 160 MHz channel width to new style as interop
* workaround.
@@ -109,8 +119,7 @@
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 ==
- CONF_OPER_CHWIDTH_80P80MHZ) {
+ } else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
/*
* Convert 80+80 MHz channel width to new style as interop
* workaround.
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 23a352c..153ee40 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -643,6 +643,133 @@
}
+
+static const char * wnm_event_type2str(enum wnm_event_report_type wtype)
+{
+#define W2S(wtype) case WNM_EVENT_TYPE_ ## wtype: return #wtype;
+ switch (wtype) {
+ W2S(TRANSITION)
+ W2S(RSNA)
+ W2S(P2P_LINK)
+ W2S(WNM_LOG)
+ W2S(BSS_COLOR_COLLISION)
+ W2S(BSS_COLOR_IN_USE)
+ }
+ return "UNKNOWN";
+#undef W2S
+}
+
+
+static void ieee802_11_rx_wnm_event_report(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *buf,
+ size_t len)
+{
+ struct sta_info *sta;
+ u8 dialog_token;
+ struct wnm_event_report_element *report_ie;
+ const u8 *pos = buf, *end = buf + len;
+ const size_t fixed_field_len = 3; /* Event Token/Type/Report Status */
+#ifdef CONFIG_IEEE80211AX
+ const size_t tsf_len = 8;
+ u8 color;
+ u64 bitmap;
+#endif /* CONFIG_IEEE80211AX */
+
+ if (end - pos < 1 + 2) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore too short WNM Event Report frame from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ dialog_token = *pos++;
+ report_ie = (struct wnm_event_report_element *) pos;
+
+ if (end - pos < 2 + report_ie->len ||
+ report_ie->len < fixed_field_len) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore truncated WNM Event Report frame from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ if (report_ie->eid != WLAN_EID_EVENT_REPORT ||
+ report_ie->status != WNM_STATUS_SUCCESSFUL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WNM: Received WNM Event Report frame from "
+ MACSTR " dialog_token=%u event_token=%u type=%d (%s)",
+ MAC2STR(addr), dialog_token, report_ie->token,
+ report_ie->type, wnm_event_type2str(report_ie->type));
+
+ pos += 2 + fixed_field_len;
+ wpa_hexdump(MSG_MSGDUMP, "WNM: Event Report", pos, end - pos);
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for received WNM Event Report",
+ MAC2STR(addr));
+ return;
+ }
+
+ switch (report_ie->type) {
+#ifdef CONFIG_IEEE80211AX
+ case WNM_EVENT_TYPE_BSS_COLOR_COLLISION:
+ if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
+ return;
+ if (report_ie->len <
+ fixed_field_len + tsf_len + 8) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BSS color collision event report from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+ bitmap = WPA_GET_LE64(report_ie->u.bss_color_collision.color_bitmap);
+ wpa_printf(MSG_DEBUG,
+ "WNM: BSS color collision bitmap 0x%llx reported by "
+ MACSTR, (unsigned long long) bitmap, MAC2STR(addr));
+ hostapd_switch_color(hapd->iface->bss[0], bitmap);
+ break;
+ case WNM_EVENT_TYPE_BSS_COLOR_IN_USE:
+ if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
+ return;
+ if (report_ie->len < fixed_field_len + tsf_len + 1) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BSS color in use event report from "
+ MACSTR, MAC2STR(addr));
+ return;
+ }
+ color = report_ie->u.bss_color_in_use.color;
+ if (color > 63) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Invalid BSS color %u report from "
+ MACSTR, color, MAC2STR(addr));
+ return;
+ }
+ if (color == 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: BSS color use report canceled by "
+ MACSTR, MAC2STR(addr));
+ /* TODO: Clear stored color from the collision bitmap
+ * if there are no other users for it. */
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "WNM: BSS color %u use report by "
+ MACSTR, color, MAC2STR(addr));
+ hapd->color_collision_bitmap |= 1ULL << color;
+ break;
+#endif /* CONFIG_IEEE80211AX */
+ default:
+ wpa_printf(MSG_DEBUG,
+ "WNM Event Report type=%d (%s) not supported",
+ report_ie->type,
+ wnm_event_type2str(report_ie->type));
+ break;
+ }
+}
+
+
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -658,6 +785,10 @@
plen = len - IEEE80211_HDRLEN - 2;
switch (action) {
+ case WNM_EVENT_REPORT:
+ ieee802_11_rx_wnm_event_report(hapd, mgmt->sa, payload,
+ plen);
+ return 0;
case WNM_BSS_TRANS_MGMT_QUERY:
ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload,
plen);
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7aff64f..635a74a 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -36,7 +36,7 @@
#define STATE_MACHINE_DATA struct wpa_state_machine
#define STATE_MACHINE_DEBUG_PREFIX "WPA"
-#define STATE_MACHINE_ADDR sm->addr
+#define STATE_MACHINE_ADDR wpa_auth_get_spa(sm)
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -59,7 +59,9 @@
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk, int force_sha256);
+ struct wpa_ptk *ptk, int force_sha256,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
@@ -80,6 +82,18 @@
static const int dot11RSNAConfigSATimeout = 60;
+static const u8 * wpa_auth_get_aa(const struct wpa_state_machine *sm)
+{
+ return sm->wpa_auth->addr;
+}
+
+
+static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm)
+{
+ return sm->addr;
+}
+
+
static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
@@ -253,13 +267,14 @@
}
-void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
- const u8 *addr, int cipher)
+static void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher)
{
if (wpa_auth->cb->clear_ptksa)
wpa_auth->cb->clear_ptksa(wpa_auth->cb_ctx, addr, cipher);
}
+
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
@@ -378,7 +393,8 @@
struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_state_machine *sm = timeout_ctx;
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
+ "rekeying PTK");
wpa_request_new_ptk(sm);
wpa_sm_step(sm);
}
@@ -388,7 +404,8 @@
{
if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
- MACSTR " (%d seconds)", MAC2STR(sm->addr),
+ MACSTR " (%d seconds)",
+ MAC2STR(wpa_auth_get_spa(sm)),
sm->wpa_auth->conf.wpa_ptk_rekey);
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
@@ -695,7 +712,7 @@
#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"FT authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
@@ -706,7 +723,7 @@
#ifdef CONFIG_FILS
if (sm->fils_completed) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"FILS authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
@@ -721,7 +738,7 @@
return wpa_sm_step(sm);
}
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"start authentication");
sm->started = 1;
@@ -755,7 +772,8 @@
MACSTR " (bit %u)",
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
- MAC2STR(sm->addr), sm->ip_addr_bit);
+ MAC2STR(wpa_auth_get_spa(sm)),
+ sm->ip_addr_bit);
bitfield_clear(sm->wpa_auth->ip_pool, sm->ip_addr_bit);
}
#endif /* CONFIG_P2P */
@@ -787,7 +805,7 @@
wpa_auth = sm->wpa_auth;
if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"strict rekeying - force GTK rekey since STA is leaving");
if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk,
wpa_auth, NULL) == -1)
@@ -807,7 +825,7 @@
* Freeing will be completed in the end of wpa_sm_step(). */
wpa_printf(MSG_DEBUG,
"WPA: Registering pending STA state machine deinit for "
- MACSTR, MAC2STR(sm->addr));
+ MACSTR, MAC2STR(wpa_auth_get_spa(sm)));
sm->pending_deinit = 1;
} else
wpa_free_sta_sm(sm);
@@ -822,7 +840,7 @@
if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
wpa_printf(MSG_INFO,
"WPA: PTK0 rekey not allowed, disconnect " MACSTR,
- MAC2STR(sm->addr));
+ MAC2STR(wpa_auth_get_spa(sm)));
sm->Disconnect = true;
/* Try to encourage the STA to reconnect */
sm->disconnect_reason =
@@ -920,18 +938,19 @@
struct wpa_state_machine *sm, int group)
{
/* Supplicant reported a Michael MIC error */
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))",
group);
if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"ignore Michael MIC failure report since group cipher is not TKIP");
} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"ignore Michael MIC failure report since pairwise cipher is not TKIP");
} else {
- if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+ if (wpa_auth_mic_failure_report(wpa_auth,
+ wpa_auth_get_spa(sm)) > 0)
return 1; /* STA entry was removed */
sm->dot11RSNAStatsTKIPRemoteMICFailures++;
wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
@@ -954,6 +973,10 @@
const u8 *pmk = NULL;
size_t pmk_len;
int vlan_id = 0;
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t key_len;
+ int ret = -1;
os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
@@ -975,8 +998,8 @@
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
- 0)
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0,
+ pmk_r0, pmk_r1, pmk_r0_name, &key_len) < 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -997,7 +1020,7 @@
if (!ok) {
wpa_printf(MSG_DEBUG,
"WPA: Earlier SNonce did not result in matching MIC");
- return -1;
+ goto fail;
}
wpa_printf(MSG_DEBUG,
@@ -1006,14 +1029,26 @@
if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
- return -1;
+ goto fail;
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) {
+ wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1");
+ wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name,
+ key_len);
+ }
+#endif /* CONFIG_IEEE80211R_AP */
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = true;
- return 0;
+ ret = 0;
+fail:
+ forced_memzero(pmk_r0, sizeof(pmk_r0));
+ forced_memzero(pmk_r1, sizeof(pmk_r1));
+ return ret;
}
@@ -1063,7 +1098,7 @@
key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
" key_info=0x%x type=%u mic_len=%zu key_data_length=%u",
- MAC2STR(sm->addr), key_info, key->type,
+ MAC2STR(wpa_auth_get_spa(sm)), key_info, key->type,
mic_len, key_data_length);
wpa_hexdump(MSG_MSGDUMP,
"WPA: EAPOL-Key header (ending before Key MIC)",
@@ -1138,7 +1173,7 @@
if (wpa_use_cmac(sm->wpa_key_mgmt) &&
!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
- wpa_auth_logger(wpa_auth, sm->addr,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_WARNING,
"advertised support for AES-128-CMAC, but did not use it");
return;
@@ -1147,7 +1182,7 @@
if (!wpa_use_cmac(sm->wpa_key_mgmt) &&
!wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
- wpa_auth_logger(wpa_auth, sm->addr,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_WARNING,
"did not use HMAC-SHA1-AES with CCMP/GCMP");
return;
@@ -1156,7 +1191,8 @@
if (wpa_use_akm_defined(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_WARNING,
"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
return;
}
@@ -1166,7 +1202,8 @@
if (sm->req_replay_counter_used &&
os_memcmp(key->replay_counter, sm->req_replay_counter,
WPA_REPLAY_COUNTER_LEN) <= 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_WARNING,
"received EAPOL-Key request with replayed counter");
return;
}
@@ -1189,7 +1226,8 @@
* pending requests, so allow the SNonce to be updated
* even if we have already sent out EAPOL-Key 3/4.
*/
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"Process SNonce update from STA based on retransmitted EAPOL-Key 1/4");
sm->update_snonce = 1;
os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
@@ -1209,7 +1247,8 @@
* there was two EAPOL-Key 2/4 messages and they had
* different SNonce values.
*/
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
goto continue_processing;
}
@@ -1218,11 +1257,13 @@
wpa_replay_counter_valid(sm->prev_key_replay,
key->replay_counter) &&
sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"ignore retransmitted EAPOL-Key %s - SNonce did not change",
msgtxt);
} else {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"received EAPOL-Key %s with unexpected replay counter",
msgtxt);
}
@@ -1242,7 +1283,7 @@
#ifdef CONFIG_FILS
if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 &&
!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame");
return;
}
@@ -1254,7 +1295,8 @@
sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING &&
(!sm->update_snonce ||
sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key msg 2/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
@@ -1281,7 +1323,8 @@
case PAIRWISE_4:
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
!sm->PTK_valid) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key msg 4/4 in invalid state (%d) - dropped",
sm->wpa_ptk_state);
return;
@@ -1290,7 +1333,8 @@
case GROUP_2:
if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
|| !sm->PTK_valid) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key msg 2/2 in invalid state (%d) - dropped",
sm->wpa_ptk_group_state);
return;
@@ -1300,18 +1344,18 @@
break;
}
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"received EAPOL-Key frame (%s)", msgtxt);
if (key_info & WPA_KEY_INFO_ACK) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"received invalid EAPOL-Key: Key Ack set");
return;
}
if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
!(key_info & WPA_KEY_INFO_MIC)) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"received invalid EAPOL-Key: Key MIC not set");
return;
}
@@ -1319,7 +1363,7 @@
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
(key_info & WPA_KEY_INFO_MIC)) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"received invalid EAPOL-Key: Key MIC set");
return;
}
@@ -1332,7 +1376,8 @@
data, data_len) &&
(msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
wpa_try_alt_snonce(sm, data, data_len))) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
#ifdef TEST_FUZZ
wpa_printf(MSG_INFO,
@@ -1345,7 +1390,8 @@
if (!mic_len &&
wpa_aead_decrypt(sm, &sm->PTK, data, data_len,
&key_data_length) < 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
#ifdef TEST_FUZZ
wpa_printf(MSG_INFO,
@@ -1369,7 +1415,8 @@
os_memcpy(sm->req_replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
} else {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key request with invalid MIC");
return;
}
@@ -1385,7 +1432,8 @@
!(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key Request for new 4-Way Handshake");
wpa_request_new_ptk(sm);
} else if (key_data_length > 0 &&
@@ -1393,7 +1441,8 @@
&kde) == 0 &&
kde.mac_addr) {
} else {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"received EAPOL-Key Request for GTK rekeying");
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
if (wpa_auth_gtk_rekey_in_process(wpa_auth))
@@ -1504,7 +1553,8 @@
}
sm->pending_1_of_4_timeout = 0;
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
+ "EAPOL-Key timeout");
sm->TimeoutEvt = true;
wpa_sm_step(sm);
}
@@ -1696,7 +1746,8 @@
if (key_info & WPA_KEY_INFO_MIC) {
if (!sm->PTK_valid || !mic_len) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key frame");
os_free(hdr);
return;
@@ -1712,7 +1763,8 @@
if (!pairwise &&
conf->corrupt_gtk_rekey_mic_probability > 0.0 &&
drand48() < conf->corrupt_gtk_rekey_mic_probability) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
key_mic[0]++;
}
@@ -1842,7 +1894,7 @@
if (!sm)
return -1;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"event %d notification", event);
switch (event) {
@@ -1902,7 +1954,7 @@
sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
wpa_printf(MSG_INFO,
"WPA: PTK0 rekey not allowed, disconnect "
- MACSTR, MAC2STR(sm->addr));
+ MACSTR, MAC2STR(wpa_auth_get_spa(sm)));
sm->Disconnect = true;
/* Try to encourage the STA to reconnect */
sm->disconnect_reason =
@@ -2149,7 +2201,8 @@
sm->disconnect_reason = WLAN_REASON_INVALID_PMKID;
return;
#endif /* CONFIG_DPP */
- } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
+ } else if (wpa_auth_get_msk(sm->wpa_auth, wpa_auth_get_spa(sm),
+ msk, &len) == 0) {
unsigned int pmk_len;
if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
@@ -2257,7 +2310,7 @@
return;
}
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"sending 1/4 msg of 4-Way Handshake");
/*
* For infrastructure BSS cases, it is better for the AP not to include
@@ -2336,8 +2389,10 @@
* Calculate PMKID since no PMKSA cache entry was
* available with pre-calculated PMKID.
*/
- rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
- sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
+ rsn_pmkid(sm->PMK, sm->pmk_len,
+ wpa_auth_get_aa(sm),
+ wpa_auth_get_spa(sm),
+ &pmkid[2 + RSN_SELECTOR_LEN],
sm->wpa_key_mgmt);
wpa_hexdump(MSG_DEBUG,
"RSN: Message 1/4 PMKID derived from PMK",
@@ -2356,7 +2411,9 @@
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk, int force_sha256)
+ struct wpa_ptk *ptk, int force_sha256,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len)
{
const u8 *z = NULL;
size_t z_len = 0, kdk_len;
@@ -2377,12 +2434,15 @@
ret = wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
sm->SNonce, sm->ANonce,
- sm->addr, sm->wpa_auth->addr,
+ wpa_auth_get_spa(sm),
+ wpa_auth_get_aa(sm),
sm->pmk_r1_name, ptk,
ptk_name, sm->wpa_key_mgmt,
sm->pairwise, kdk_len);
} else {
- ret = wpa_auth_derive_ptk_ft(sm, ptk);
+ ret = wpa_auth_derive_ptk_ft(sm, ptk, pmk_r0, pmk_r1,
+ pmk_r0_name, key_len,
+ kdk_len);
}
if (ret) {
wpa_printf(MSG_ERROR, "FT: PTK derivation failed");
@@ -2416,9 +2476,9 @@
if (force_sha256)
akmp |= WPA_KEY_MGMT_PSK_SHA256;
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);
+ wpa_auth_get_aa(sm), wpa_auth_get_spa(sm),
+ sm->ANonce, snonce, ptk, akmp,
+ sm->pairwise, z, z_len, kdk_len);
if (ret) {
wpa_printf(MSG_DEBUG,
"WPA: PTK derivation failed");
@@ -2459,7 +2519,8 @@
else
kdk_len = 0;
- res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
+ res = fils_pmk_to_ptk(pmk, pmk_len, wpa_auth_get_spa(sm),
+ wpa_auth_get_aa(sm),
snonce, anonce, dhss, dhss_len,
&sm->PTK, ick, &ick_len,
sm->wpa_key_mgmt, sm->pairwise,
@@ -2493,7 +2554,7 @@
conf->mobility_domain,
conf->r0_key_holder,
conf->r0_key_holder_len,
- sm->addr, pmk_r0, pmk_r0_name,
+ wpa_auth_get_spa(sm), pmk_r0, pmk_r0_name,
sm->wpa_key_mgmt) < 0)
return -1;
@@ -2501,7 +2562,8 @@
forced_memzero(fils_ft, sizeof(fils_ft));
res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
- sm->addr, sm->pmk_r1_name,
+ wpa_auth_get_spa(sm),
+ sm->pmk_r1_name,
fils_ft_len);
forced_memzero(pmk_r0, PMK_LEN_MAX);
if (res < 0)
@@ -2513,7 +2575,8 @@
#endif /* CONFIG_IEEE80211R_AP */
res = fils_key_auth_sk(ick, ick_len, snonce, anonce,
- sm->addr, sm->wpa_auth->addr,
+ wpa_auth_get_spa(sm),
+ wpa_auth_get_aa(sm),
g_sta ? wpabuf_head(g_sta) : NULL,
g_sta ? wpabuf_len(g_sta) : 0,
g_ap ? wpabuf_head(g_ap) : NULL,
@@ -2548,7 +2611,7 @@
key_data_len = WPA_GET_BE16(pos);
if (key_data_len < AES_BLOCK_SIZE ||
key_data_len > buf_len - sizeof(*hdr) - sizeof(*key) - 2) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"No room for AES-SIV data in the frame");
return -1;
}
@@ -2564,7 +2627,7 @@
aad_len[0] = pos - buf;
if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, key_data_len,
1, aad, aad_len, tmp) < 0) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"Invalid AES-SIV data in the frame");
bin_clear_free(tmp, key_data_len);
return -1;
@@ -3067,6 +3130,9 @@
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t key_len;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = false;
@@ -3105,7 +3171,8 @@
}
if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
- owe_ptk_workaround == 2) < 0)
+ owe_ptk_workaround == 2, pmk_r0, pmk_r1,
+ pmk_r0_name, &key_len) < 0)
break;
if (mic_len &&
@@ -3154,15 +3221,16 @@
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len);
sm->waiting_radius_psk = 1;
- return;
+ goto out;
}
if (!ok) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
if (psk_found)
wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
- return;
+ goto out;
}
/*
@@ -3176,12 +3244,12 @@
key_data_length = WPA_GET_BE16(mic + mic_len);
if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
sizeof(*key) - mic_len - 2)
- return;
+ goto out;
if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"received EAPOL-Key msg 2/4 with invalid Key Data contents");
- return;
+ goto out;
}
if (kde.rsn_ie) {
eapol_key_ie = kde.rsn_ie;
@@ -3197,7 +3265,7 @@
if (!sm->wpa_ie ||
wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
eapol_key_ie, eapol_key_ie_len)) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"WPA IE from (Re)AssocReq did not match with msg 2/4");
if (sm->wpa_ie) {
wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
@@ -3208,14 +3276,14 @@
/* MLME-DEAUTHENTICATE.request */
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
if ((!sm->rsnxe && kde.rsnxe) ||
(sm->rsnxe && !kde.rsnxe) ||
(sm->rsnxe && kde.rsnxe &&
(sm->rsnxe_len != kde.rsnxe_len ||
os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
sm->rsnxe, sm->rsnxe_len);
@@ -3224,7 +3292,7 @@
/* MLME-DEAUTHENTICATE.request */
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
@@ -3234,33 +3302,37 @@
enum oci_verify_result res;
if (wpa_channel_info(wpa_auth, &ci) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
- return;
+ goto out;
}
if (get_sta_tx_parameters(sm,
channel_width_to_int(ci.chanwidth),
ci.seg1_idx, &tx_chanwidth,
&tx_seg1_idx) < 0)
- return;
+ goto out;
res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
tx_chanwidth, tx_seg1_idx);
if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
/* Work around misbehaving STAs */
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"Disable OCV with a STA that does not send OCI");
wpa_auth_set_ocv(sm, 0);
} else if (res != OCI_SUCCESS) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"OCV failed: %s", ocv_errorstr);
if (wpa_auth->conf.msg_ctx)
wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
OCV_FAILURE "addr=" MACSTR
" frame=eapol-key-m2 error=%s",
- MAC2STR(sm->addr), ocv_errorstr);
- return;
+ MAC2STR(wpa_auth_get_spa(sm)),
+ ocv_errorstr);
+ goto out;
}
}
#endif /* CONFIG_OCV */
@@ -3268,7 +3340,7 @@
if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
@@ -3288,7 +3360,8 @@
MACSTR " (bit %u)",
sm->ip_addr[0], sm->ip_addr[1],
sm->ip_addr[2], sm->ip_addr[3],
- MAC2STR(sm->addr), sm->ip_addr_bit);
+ MAC2STR(wpa_auth_get_spa(sm)),
+ sm->ip_addr_bit);
}
}
#endif /* CONFIG_P2P */
@@ -3306,7 +3379,7 @@
"DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association");
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
}
#endif /* CONFIG_DPP2 */
@@ -3319,14 +3392,15 @@
*/
if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
WPA_PMK_NAME_LEN) != 0) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"PMKR1Name mismatch in FT 4-way handshake");
wpa_hexdump(MSG_DEBUG,
"FT: PMKR1Name from Supplicant",
sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
- return;
+ goto out;
}
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -3335,7 +3409,7 @@
wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
sm->pending_1_of_4_timeout = 0;
@@ -3351,9 +3425,20 @@
sm->MICVerified = true;
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) {
+ wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1");
+ wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name,
+ key_len);
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = true;
+out:
+ forced_memzero(pmk_r0, sizeof(pmk_r0));
+ forced_memzero(pmk_r1, sizeof(pmk_r1));
}
@@ -3577,7 +3662,7 @@
wpa_ie = wpa_ie_buf;
}
#endif /* CONFIG_TESTING_OPTIONS */
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"sending 3/4 msg of 4-Way Handshake");
if (sm->wpa == WPA_VERSION_WPA2) {
if (sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
@@ -3639,7 +3724,8 @@
* by setting the Secure bit here even in the case of
* WPA if the supplicant used it first.
*/
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
@@ -3865,14 +3951,14 @@
sm->PInitAKeys = true;
else
sm->has_GTK = true;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"pairwise key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO, "EAPOL-4WAY-HS-COMPLETED "
MACSTR, MAC2STR(sm->addr));
#ifdef CONFIG_IEEE80211R_AP
- wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
+ wpa_ft_push_pmk_r1(sm->wpa_auth, wpa_auth_get_spa(sm));
#endif /* CONFIG_IEEE80211R_AP */
sm->ptkstart_without_success = 0;
@@ -3888,7 +3974,7 @@
SM_ENTER(WPA_PTK, INITIALIZE);
else if (sm->Disconnect
/* || FIX: dot11RSNAConfigSALifetime timeout */) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"WPA_PTK: sm->Disconnect");
SM_ENTER(WPA_PTK, DISCONNECT);
}
@@ -3937,7 +4023,8 @@
#endif /* CONFIG_DPP */
} else {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"INITPMK - keyAvailable = false");
SM_ENTER(WPA_PTK, DISCONNECT);
}
@@ -3956,7 +4043,8 @@
"INITPSK: No PSK yet available for STA - use RADIUS later");
SM_ENTER(WPA_PTK, PTKSTART);
} else {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"no PSK configured for the STA");
wpa_auth->dot11RSNA4WayHandshakeFailures++;
SM_ENTER(WPA_PTK, DISCONNECT);
@@ -3968,7 +4056,8 @@
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"PTKSTART: Retry limit %u reached",
conf->wpa_pairwise_update_count);
sm->disconnect_reason =
@@ -4000,7 +4089,8 @@
(conf->wpa_disable_eapol_key_retries &&
sm->TimeoutCtr > 1)) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"PTKINITNEGOTIATING: Retry limit %u reached",
conf->wpa_pairwise_update_count);
sm->disconnect_reason =
@@ -4057,7 +4147,7 @@
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
@@ -4138,7 +4228,7 @@
return;
if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"received EAPOL-Key group msg 2/2 with invalid Key Data contents");
return;
}
@@ -4149,7 +4239,8 @@
int tx_seg1_idx;
if (wpa_channel_info(wpa_auth, &ci) != 0) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"Failed to get channel info to validate received OCI in EAPOL-Key group 2/2");
return;
}
@@ -4163,13 +4254,15 @@
if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
tx_chanwidth, tx_seg1_idx) !=
OCI_SUCCESS) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_INFO,
"OCV failed: %s", ocv_errorstr);
if (wpa_auth->conf.msg_ctx)
wpa_msg(wpa_auth->conf.msg_ctx, MSG_INFO,
OCV_FAILURE "addr=" MACSTR
" frame=eapol-key-g2 error=%s",
- MAC2STR(sm->addr), ocv_errorstr);
+ MAC2STR(wpa_auth_get_spa(sm)),
+ ocv_errorstr);
return;
}
}
@@ -4180,7 +4273,7 @@
sm->GUpdateStationKeys = false;
sm->GTimeoutCtr = 0;
/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"group key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
sm->has_GTK = true;
@@ -4195,7 +4288,7 @@
sm->GUpdateStationKeys = false;
sm->Disconnect = true;
sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"group key handshake failed (%s) after %u tries",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
sm->wpa_auth->conf.wpa_group_update_count);
@@ -4308,7 +4401,8 @@
return 0;
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
sm->GUpdateStationKeys = false;
return 0;
@@ -4319,7 +4413,8 @@
* Since we clear the GKeyDoneStations before the loop, the
* station needs to be counted here anyway.
*/
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"GUpdateStationKeys was already set when marking station for GTK rekeying");
}
@@ -4553,7 +4648,7 @@
if (sm->group == ctx) {
wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
" for disconnection due to fatal failure",
- MAC2STR(sm->addr));
+ MAC2STR(wpa_auth_get_spa(sm)));
sm->Disconnect = true;
}
@@ -4646,7 +4741,7 @@
if (sm->pending_deinit) {
wpa_printf(MSG_DEBUG,
"WPA: Completing pending STA state machine deinit for "
- MACSTR, MAC2STR(sm->addr));
+ MACSTR, MAC2STR(wpa_auth_get_spa(sm)));
wpa_free_sta_sm(sm);
return 1;
}
@@ -4982,7 +5077,8 @@
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
sm->PTK.kck, sm->PTK.kck_len,
- sm->wpa_auth->addr, sm->addr, session_timeout,
+ wpa_auth_get_aa(sm),
+ wpa_auth_get_spa(sm), session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
@@ -5392,7 +5488,7 @@
wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR
" to use group state machine for VLAN ID %d",
- MAC2STR(sm->addr), vlan_id);
+ MAC2STR(wpa_auth_get_spa(sm)), vlan_id);
wpa_group_get(sm->wpa_auth, group);
wpa_group_put(sm->wpa_auth, sm->group);
@@ -5408,7 +5504,7 @@
if (!wpa_auth || !sm)
return;
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
- " ack=%d", MAC2STR(sm->addr), ack);
+ " ack=%d", MAC2STR(wpa_auth_get_spa(sm)), ack);
if (sm->pending_1_of_4_timeout && ack) {
/*
* Some deployed supplicant implementations update their SNonce
@@ -5606,7 +5702,7 @@
anonce = anonce_buf;
}
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"sending 1/4 msg of 4-Way Handshake (TESTING)");
wpa_send_eapol(sm->wpa_auth, sm,
WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
@@ -5648,7 +5744,7 @@
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"sending 3/4 msg of 4-Way Handshake (TESTING)");
if (sm->wpa == WPA_VERSION_WPA2) {
/* WPA2 send GTK in the 4-way handshake */
@@ -5673,7 +5769,8 @@
* by setting the Secure bit here even in the case of
* WPA if the supplicant used it first.
*/
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ LOGGER_DEBUG,
"STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround");
secure = 1;
}
@@ -5810,7 +5907,7 @@
/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
/* Use 0 RSC */
- wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG,
"sending 1/2 msg of Group Key Handshake (TESTING)");
gtk = gsm->GTK[gsm->GN - 1];
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 88d63bb..35585cd 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -35,6 +35,9 @@
const unsigned int ftRRBseqTimeout = 10;
const unsigned int ftRRBmaxQueueLen = 100;
+/* TODO: make these configurable */
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 *current_ap, const u8 *sta_addr,
@@ -2109,11 +2112,11 @@
}
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len, size_t kdk_len)
{
- u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
size_t pmk_r0_len, pmk_r1_len;
- u8 pmk_r1[PMK_LEN_MAX];
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
@@ -2121,12 +2124,6 @@
const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
- int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
- int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
- struct vlan_description vlan;
- const u8 *identity, *radius_cui;
- size_t identity_len, radius_cui_len;
- int session_timeout;
const u8 *mpmk;
size_t mpmk_len;
@@ -2139,7 +2136,7 @@
pmk_r0_len = SHA384_MAC_LEN;
else
pmk_r0_len = PMK_LEN;
- pmk_r1_len = pmk_r0_len;
+ *key_len = pmk_r1_len = pmk_r0_len;
if (sm->xxkey_len > 0) {
mpmk = sm->xxkey;
@@ -2153,10 +2150,39 @@
return -1;
}
+ if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
+ r0kh, r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name,
+ sm->wpa_key_mgmt) < 0 ||
+ wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, sm->pmk_r1_name) < 0)
+ return -1;
+
+ return wpa_pmk_r1_to_ptk(pmk_r1, 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);
+}
+
+
+void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0,
+ const u8 *pmk_r1, const u8 *pmk_r0_name,
+ size_t key_len)
+{
+ int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
+ int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len, radius_cui_len;
+ int session_timeout;
+
+ if (psk_local && wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
+ return;
+
if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
MAC2STR(sm->addr));
- return -1;
+ return;
}
identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
@@ -2164,31 +2190,16 @@
&radius_cui);
session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
- if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
- r0kh, r0kh_len, sm->addr,
- pmk_r0, pmk_r0_name,
- sm->wpa_key_mgmt) < 0)
- return -1;
- if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
- wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
- pmk_r0_name,
- sm->pairwise, &vlan, expires_in,
- session_timeout, identity, identity_len,
- radius_cui, radius_cui_len);
- if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, sm->pmk_r1_name) < 0)
- return -1;
- if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
- wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
- sm->pmk_r1_name, sm->pairwise, &vlan,
- expires_in, session_timeout, identity,
- identity_len, radius_cui, radius_cui_len);
-
- return wpa_pmk_r1_to_ptk(pmk_r1, 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,
- 0);
+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, key_len,
+ pmk_r0_name,
+ sm->pairwise, &vlan, expires_in,
+ session_timeout, identity, identity_len,
+ radius_cui, radius_cui_len);
+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, key_len,
+ sm->pmk_r1_name, sm->pairwise, &vlan,
+ expires_in, session_timeout, identity,
+ identity_len, radius_cui, radius_cui_len);
}
@@ -2941,6 +2952,9 @@
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
sm->pairwise_set = true;
sm->tk_already_set = true;
+
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 7ed3f2b..d401550 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -296,6 +296,9 @@
int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx);
+void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk);
#ifdef CONFIG_IEEE80211R_AP
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
@@ -304,7 +307,12 @@
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len, int rsnxe_used);
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len, size_t kdk_len);
+void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0,
+ const u8 *pmk_r1, const u8 *pmk_r0_name,
+ size_t key_len);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
index e2c4e10..625f405 100644
--- a/src/ap/wpa_auth_kay.c
+++ b/src/ap/wpa_auth_kay.c
@@ -327,6 +327,7 @@
res = ieee802_1x_kay_init(kay_ctx, policy,
hapd->conf->macsec_replay_protect,
hapd->conf->macsec_replay_window,
+ hapd->conf->macsec_offload,
hapd->conf->macsec_port,
hapd->conf->mka_priority,
hapd->conf->macsec_csindex,
@@ -352,33 +353,6 @@
}
-static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd,
- struct sta_info *sta, u8 *sid,
- size_t *len)
-{
- const u8 *session_id;
- size_t id_len, need_len;
-
- session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len);
- if (!session_id) {
- wpa_printf(MSG_DEBUG,
- "MACsec: Failed to get SessionID from EAPOL state machines");
- return -1;
- }
-
- need_len = 1 + 2 * 32 /* random size */;
- if (need_len > id_len) {
- wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough");
- return -1;
- }
-
- os_memcpy(sid, session_id, need_len);
- *len = need_len;
-
- return 0;
-}
-
-
static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd,
struct sta_info *sta, u8 *msk, size_t *len)
{
@@ -410,8 +384,8 @@
void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd,
struct sta_info *sta)
{
- u8 *sid;
- size_t sid_len = 128;
+ const u8 *sid;
+ size_t sid_len;
struct mka_key_name *ckn;
struct mka_key *cak;
struct mka_key *msk;
@@ -425,10 +399,9 @@
MACSTR, MAC2STR(sta->addr));
msk = os_zalloc(sizeof(*msk));
- sid = os_zalloc(sid_len);
ckn = os_zalloc(sizeof(*ckn));
cak = os_zalloc(sizeof(*cak));
- if (!msk || !sid || !ckn || !cak)
+ if (!msk || !ckn || !cak)
goto fail;
msk->len = DEFAULT_KEY_LEN;
@@ -437,8 +410,8 @@
goto fail;
}
- if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len))
- {
+ sid = ieee802_1x_get_session_id(sta->eapol_sm, &sid_len);
+ if (!sid) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Could not get EAP Session Id");
goto fail;
@@ -470,7 +443,6 @@
fail:
bin_clear_free(msk, sizeof(*msk));
- os_free(sid);
os_free(ckn);
bin_clear_free(cak, sizeof(*cak));
diff --git a/src/common/dpp.c b/src/common/dpp.c
index d2fc00f..02c32dc 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1310,8 +1310,14 @@
auth->conf_sta = conf_sta;
auth->conf_ap = conf_ap;
} else if (idx == 1) {
- auth->conf2_sta = conf_sta;
- auth->conf2_ap = conf_ap;
+ if (!auth->conf_sta)
+ auth->conf_sta = conf_sta;
+ else
+ auth->conf2_sta = conf_sta;
+ if (!auth->conf_ap)
+ auth->conf_ap = conf_ap;
+ else
+ auth->conf2_ap = conf_ap;
} else {
goto fail;
}
@@ -1342,7 +1348,7 @@
goto fail;
os_memcpy(tmp, cmd, len);
tmp[len] = '\0';
- res = dpp_configuration_parse_helper(auth, cmd, 0);
+ res = dpp_configuration_parse_helper(auth, tmp, 0);
str_clear_free(tmp);
if (res)
goto fail;
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 6646301..584c6d2 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -876,3 +876,70 @@
return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
}
+
+
+/* IEEE P802.11be/D3.0, Table 36-30 - Definition of the Punctured Channel
+ * Information field in the U-SIG for an EHT MU PPDU using non-OFDMA
+ * transmissions */
+static const u16 punct_bitmap_80[] = { 0xF, 0xE, 0xD, 0xB, 0x7 };
+static const u16 punct_bitmap_160[] = {
+ 0xFF, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF,
+ 0x7F, 0xFC, 0xF3, 0xCF, 0x3F
+};
+static const u16 punct_bitmap_320[] = {
+ 0xFFFF, 0xFFFC, 0xFFF3, 0xFFCF, 0xFF3F, 0xFCFF, 0xF3FF, 0xCFFF,
+ 0x3FFF, 0xFFF0, 0xFF0F, 0xF0FF, 0x0FFF, 0xFFC0, 0xFF30, 0xFCF0,
+ 0xF3F0, 0xCFF0, 0x3FF0, 0x0FFC, 0x0FF3, 0x0FCF, 0x0F3F, 0x0CFF,
+ 0x03FF
+};
+
+
+bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap)
+{
+ u8 i, count;
+ u16 bitmap;
+ const u16 *valid_bitmaps;
+
+ if (!punct_bitmap) /* All channels active */
+ return true;
+
+ bitmap = ~punct_bitmap;
+
+ switch (bw) {
+ case 80:
+ bitmap &= 0xF;
+ valid_bitmaps = punct_bitmap_80;
+ count = ARRAY_SIZE(punct_bitmap_80);
+ break;
+
+ case 160:
+ bitmap &= 0xFF;
+ valid_bitmaps = punct_bitmap_160;
+ count = ARRAY_SIZE(punct_bitmap_160);
+ break;
+
+ case 320:
+ bitmap &= 0xFFFF;
+ valid_bitmaps = punct_bitmap_320;
+ count = ARRAY_SIZE(punct_bitmap_320);
+ break;
+
+ default:
+ return false;
+ }
+
+ if (!bitmap) /* No channel active */
+ return false;
+
+ if (!(bitmap & BIT(pri_ch_bit_pos))) {
+ wpa_printf(MSG_DEBUG, "Primary channel cannot be punctured");
+ return false;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (valid_bitmaps[i] == bitmap)
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index d8ca168..82e0282 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -54,5 +54,6 @@
int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
int ht40_plus, int pri);
int chan_pri_allowed(const struct hostapd_channel_data *chan);
+bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap);
#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 3c3667f..cd1b198 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -416,23 +416,13 @@
}
-/**
- * ieee802_11_parse_elems - Parse information elements in management frames
- * @start: Pointer to the start of IEs
- * @len: Length of IE buffer in octets
- * @elems: Data structure for parsed elements
- * @show_errors: Whether to show parsing errors in debug log
- * Returns: Parsing result
- */
-ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
- struct ieee802_11_elems *elems,
- int show_errors)
+static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ int show_errors)
{
const struct element *elem;
int unknown = 0;
- os_memset(elems, 0, sizeof(*elems));
-
if (!start)
return ParseOK;
@@ -684,6 +674,431 @@
}
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ int show_errors)
+{
+ os_memset(elems, 0, sizeof(*elems));
+
+ return __ieee802_11_parse_elems(start, len, elems, show_errors);
+}
+
+
+/**
+ * ieee802_11_elems_clear_ids - Clear the data for the given element IDs
+ * @ids: Array of element IDs for which data should be cleared.
+ * @num: The number of entries in the array
+ */
+void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems,
+ const u8 *ids, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ switch (ids[i]) {
+ case WLAN_EID_SSID:
+ elems->ssid = NULL;
+ elems->ssid_len = 0;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ elems->supp_rates = NULL;
+ elems->supp_rates_len = 0;
+ break;
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = NULL;
+ break;
+ case WLAN_EID_CHALLENGE:
+ elems->challenge = NULL;
+ elems->challenge_len = 0;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = NULL;
+ break;
+ case WLAN_EID_EXT_SUPP_RATES:
+ elems->ext_supp_rates = NULL;
+ elems->ext_supp_rates_len = 0;
+ break;
+ case WLAN_EID_RSN:
+ elems->rsn_ie = NULL;
+ elems->rsn_ie_len = 0;
+ break;
+ case WLAN_EID_RSNX:
+ elems->rsnxe = NULL;
+ elems->rsnxe_len = 0;
+ break;
+ case WLAN_EID_PWR_CAPABILITY:
+ elems->power_capab = NULL;
+ elems->power_capab_len = 0;
+ break;
+ case WLAN_EID_SUPPORTED_CHANNELS:
+ elems->supp_channels = NULL;
+ elems->supp_channels_len = 0;
+ break;
+ case WLAN_EID_MOBILITY_DOMAIN:
+ elems->mdie = NULL;
+ elems->mdie_len = 0;
+ break;
+ case WLAN_EID_FAST_BSS_TRANSITION:
+ elems->ftie = NULL;
+ elems->ftie_len = 0;
+ break;
+ case WLAN_EID_TIMEOUT_INTERVAL:
+ elems->timeout_int = NULL;
+ break;
+ case WLAN_EID_HT_CAP:
+ elems->ht_capabilities = NULL;
+ break;
+ case WLAN_EID_HT_OPERATION:
+ elems->ht_operation = NULL;
+ break;
+ case WLAN_EID_MESH_CONFIG:
+ elems->mesh_config = NULL;
+ elems->mesh_config_len = 0;
+ break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = NULL;
+ elems->mesh_id_len = 0;
+ break;
+ case WLAN_EID_PEER_MGMT:
+ elems->peer_mgmt = NULL;
+ elems->peer_mgmt_len = 0;
+ break;
+ case WLAN_EID_VHT_CAP:
+ elems->vht_capabilities = NULL;
+ break;
+ case WLAN_EID_VHT_OPERATION:
+ elems->vht_operation = NULL;
+ break;
+ case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
+ elems->vht_opmode_notif = NULL;
+ break;
+ case WLAN_EID_LINK_ID:
+ elems->link_id = NULL;
+ break;
+ case WLAN_EID_INTERWORKING:
+ elems->interworking = NULL;
+ elems->interworking_len = 0;
+ break;
+ case WLAN_EID_QOS_MAP_SET:
+ elems->qos_map_set = NULL;
+ elems->qos_map_set_len = 0;
+ break;
+ case WLAN_EID_EXT_CAPAB:
+ elems->ext_capab = NULL;
+ elems->ext_capab_len = 0;
+ break;
+ case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+ elems->bss_max_idle_period = NULL;
+ break;
+ case WLAN_EID_SSID_LIST:
+ elems->ssid_list = NULL;
+ elems->ssid_list_len = 0;
+ break;
+ case WLAN_EID_AMPE:
+ elems->ampe = NULL;
+ elems->ampe_len = 0;
+ break;
+ case WLAN_EID_MIC:
+ elems->mic = NULL;
+ elems->mic_len = 0;
+ break;
+ case WLAN_EID_MULTI_BAND:
+ os_memset(&elems->mb_ies, 0, sizeof(elems->mb_ies));
+ elems->mb_ies.nof_ies = 0;
+ break;
+ case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
+ elems->supp_op_classes = NULL;
+ elems->supp_op_classes_len = 0;
+ break;
+ case WLAN_EID_RRM_ENABLED_CAPABILITIES:
+ elems->rrm_enabled = NULL;
+ elems->rrm_enabled_len = 0;
+ break;
+ case WLAN_EID_CAG_NUMBER:
+ elems->cag_number = NULL;
+ elems->cag_number_len = 0;
+ break;
+ case WLAN_EID_AP_CSN:
+ elems->ap_csn = NULL;
+ break;
+ case WLAN_EID_FILS_INDICATION:
+ elems->fils_indic = NULL;
+ elems->fils_indic_len = 0;
+ break;
+ case WLAN_EID_DILS:
+ elems->dils = NULL;
+ elems->dils_len = 0;
+ break;
+ case WLAN_EID_S1G_CAPABILITIES:
+ elems->s1g_capab = NULL;
+ break;
+ }
+ }
+}
+
+
+/**
+ * ieee802_11_elems_clear_ext_ids - Clear the data for the given element
+ * extension IDs
+ * @ids: Array of element extension IDs for which data should be cleared.
+ * @num: The number of entries in the array
+ */
+void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
+ const u8 *ids, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ switch (ids[i]) {
+ case WLAN_EID_EXT_ASSOC_DELAY_INFO:
+ elems->assoc_delay_info = NULL;
+ break;
+ case WLAN_EID_EXT_FILS_REQ_PARAMS:
+ elems->fils_req_params = NULL;
+ elems->fils_req_params_len = 0;
+ break;
+ case WLAN_EID_EXT_FILS_KEY_CONFIRM:
+ elems->fils_key_confirm = NULL;
+ elems->fils_key_confirm_len = 0;
+ break;
+ case WLAN_EID_EXT_FILS_SESSION:
+ elems->fils_session = NULL;
+ break;
+ case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+ elems->fils_hlp = NULL;
+ elems->fils_hlp_len = 0;
+ break;
+ case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
+ elems->fils_ip_addr_assign = NULL;
+ elems->fils_ip_addr_assign_len = 0;
+ break;
+ case WLAN_EID_EXT_KEY_DELIVERY:
+ elems->key_delivery = NULL;
+ elems->key_delivery_len = 0;
+ break;
+ case WLAN_EID_EXT_WRAPPED_DATA:
+ elems->wrapped_data = NULL;
+ elems->wrapped_data_len = 0;
+ break;
+ case WLAN_EID_EXT_FILS_PUBLIC_KEY:
+ elems->fils_pk = NULL;
+ elems->fils_pk_len = 0;
+ break;
+ case WLAN_EID_EXT_FILS_NONCE:
+ elems->fils_nonce = NULL;
+ break;
+ case WLAN_EID_EXT_OWE_DH_PARAM:
+ elems->owe_dh = NULL;
+ elems->owe_dh_len = 0;
+ break;
+ case WLAN_EID_EXT_PASSWORD_IDENTIFIER:
+ elems->password_id = NULL;
+ elems->password_id_len = 0;
+ break;
+ case WLAN_EID_EXT_HE_CAPABILITIES:
+ elems->he_capabilities = NULL;
+ elems->he_capabilities_len = 0;
+ break;
+ case WLAN_EID_EXT_HE_OPERATION:
+ elems->he_operation = NULL;
+ elems->he_operation_len = 0;
+ break;
+ case WLAN_EID_EXT_OCV_OCI:
+ elems->oci = NULL;
+ elems->oci_len = 0;
+ break;
+ case WLAN_EID_EXT_SHORT_SSID_LIST:
+ elems->short_ssid_list = NULL;
+ elems->short_ssid_list_len = 0;
+ break;
+ case WLAN_EID_EXT_HE_6GHZ_BAND_CAP:
+ elems->he_6ghz_band_cap = NULL;
+ break;
+ case WLAN_EID_EXT_PASN_PARAMS:
+ elems->pasn_params = NULL;
+ elems->pasn_params_len = 0;
+ break;
+ case WLAN_EID_EXT_MULTI_LINK:
+ elems->basic_mle = NULL;
+ elems->probe_req_mle = NULL;
+ elems->reconf_mle = NULL;
+ elems->tdls_mle = NULL;
+ elems->prior_access_mle = NULL;
+
+ elems->basic_mle_len = 0;
+ elems->probe_req_mle_len = 0;
+ elems->reconf_mle_len = 0;
+ elems->tdls_mle_len = 0;
+ elems->prior_access_mle_len = 0;
+ break;
+ case WLAN_EID_EXT_EHT_CAPABILITIES:
+ elems->eht_capabilities = NULL;
+ elems->eht_capabilities_len = 0;
+ break;
+ case WLAN_EID_EXT_EHT_OPERATION:
+ elems->eht_operation = NULL;
+ elems->eht_operation_len = 0;
+ break;
+ }
+ }
+}
+
+
+ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ struct wpabuf *mlbuf,
+ u8 link_id, bool show_errors)
+{
+ const struct ieee80211_eht_ml *ml;
+ const u8 *pos;
+ ParseRes res = ParseFailed;
+
+ pos = wpabuf_head(mlbuf);
+ len = wpabuf_len(mlbuf);
+
+ /* Must have control and common info length */
+ if (len < sizeof(*ml) + 1 || len < sizeof(*ml) + pos[sizeof(*ml)])
+ goto out;
+
+ ml = (const struct ieee80211_eht_ml *) pos;
+
+ /* As we are interested with the Per-STA profile, ignore other types */
+ if ((le_to_host16(ml->ml_control) & MULTI_LINK_CONTROL_TYPE_MASK) !=
+ MULTI_LINK_CONTROL_TYPE_BASIC)
+ goto out;
+
+ /* Skip the common info */
+ len -= sizeof(*ml) + pos[sizeof(*ml)];
+ pos += sizeof(*ml) + pos[sizeof(*ml)];
+
+ while (len > 2) {
+ size_t sub_elem_len = *(pos + 1);
+ size_t sta_info_len;
+ u16 link_info_control;
+ const u8 *non_inherit;
+
+ wpa_printf(MSG_DEBUG,
+ "MLD: sub element: len=%zu, sub_elem_len=%zu",
+ len, sub_elem_len);
+
+ if (2 + sub_elem_len > len) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: error: len=%zu, sub_elem_len=%zu",
+ len, sub_elem_len);
+ goto out;
+ }
+
+ if (*pos != 0) {
+ pos += 2 + sub_elem_len;
+ len -= 2 + sub_elem_len;
+ continue;
+ }
+
+ if (sub_elem_len < 3) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: error: sub_elem_len=%zu < 5",
+ sub_elem_len);
+ goto out;
+ }
+
+ link_info_control = WPA_GET_LE16(pos + 2);
+ if ((link_info_control & BASIC_MLE_STA_CTRL_LINK_ID_MASK) !=
+ link_id) {
+ pos += 2 + sub_elem_len;
+ len -= 2 + sub_elem_len;
+ continue;
+ }
+
+ sta_info_len = *(pos + 4);
+ if (sub_elem_len < sta_info_len + 3 || sta_info_len < 1) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: error: sub_elem_len=%zu, sta_info_len=%zu",
+ sub_elem_len, sta_info_len);
+ goto out;
+ }
+
+ pos += sta_info_len + 4;
+ sub_elem_len -= sta_info_len + 2;
+
+ if (sub_elem_len < 2) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: missing capability info");
+ goto out;
+ }
+
+ pos += 2;
+ sub_elem_len -= 2;
+
+ /* Handle non-inheritance */
+ non_inherit = get_ie_ext(pos, sub_elem_len,
+ WLAN_EID_EXT_NON_INHERITANCE);
+ if (non_inherit && non_inherit[1] > 1) {
+ u8 non_inherit_len = non_inherit[1] - 1;
+
+ /*
+ * Do not include the Non-Inheritance element when
+ * parsing below. It should be the last element in the
+ * subelement.
+ */
+ if (3U + non_inherit_len > sub_elem_len)
+ goto out;
+ sub_elem_len -= 3 + non_inherit_len;
+
+ /* Skip the ID, length and extension ID */
+ non_inherit += 3;
+
+ if (non_inherit_len < 1UL + non_inherit[0]) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: Invalid inheritance");
+ goto out;
+ }
+
+ ieee802_11_elems_clear_ids(elems, &non_inherit[1],
+ non_inherit[0]);
+
+ non_inherit_len -= 1 + non_inherit[0];
+ non_inherit += 1 + non_inherit[0];
+
+ if (non_inherit_len < 1UL + non_inherit[0]) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: Invalid inheritance");
+ goto out;
+ }
+
+ ieee802_11_elems_clear_ext_ids(elems, &non_inherit[1],
+ non_inherit[0]);
+ }
+
+ wpa_printf(MSG_DEBUG, "MLD: link: sub_elem_len=%zu",
+ sub_elem_len);
+
+ if (sub_elem_len)
+ res = __ieee802_11_parse_elems(pos, sub_elem_len,
+ elems, show_errors);
+ else
+ res = ParseOK;
+ break;
+ }
+
+out:
+ return res;
+}
+
+
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
const struct element *elem;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9a6915d..d1f7218 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -186,6 +186,14 @@
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors);
+void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems,
+ const u8 *ids, size_t num);
+void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
+ const u8 *ids, size_t num);
+ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
+ struct ieee802_11_elems *elems,
+ struct wpabuf *mlbuf,
+ u8 link_id, bool show_errors);
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index e5e4e83..9846fb4 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1965,6 +1965,42 @@
WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221,
};
+struct wnm_event_report_element {
+ u8 eid; /* WLAN_EID_EVENT_REPORT */
+ u8 len;
+ u8 token;
+ u8 type;
+ u8 status;
+ /* Followed by conditional fields */
+ union {
+ struct {
+ u8 tsf[8]; /* Event TSF */
+ u8 color_bitmap[8]; /* Event Report field */
+ } STRUCT_PACKED bss_color_collision;
+ struct {
+ u8 tsf[8]; /* Event TSF */
+ u8 color; /* Event Report field */
+ } STRUCT_PACKED bss_color_in_use;
+ } u;
+} STRUCT_PACKED;
+
+enum wnm_event_report_status {
+ WNM_STATUS_SUCCESSFUL = 0,
+ WNM_STATUS_REQ_FAILED = 1,
+ WNM_STATUS_REQ_REFUSED = 2,
+ WNM_STATUS_REQ_INCAPABLE = 3,
+ WNM_STATUS_FREQUENT_TRANSITION = 4,
+};
+
+enum wnm_event_report_type {
+ WNM_EVENT_TYPE_TRANSITION = 0,
+ WNM_EVENT_TYPE_RSNA = 1,
+ WNM_EVENT_TYPE_P2P_LINK = 2,
+ WNM_EVENT_TYPE_WNM_LOG = 3,
+ WNM_EVENT_TYPE_BSS_COLOR_COLLISION = 4,
+ WNM_EVENT_TYPE_BSS_COLOR_IN_USE = 5,
+};
+
/* Channel Switch modes (802.11h) */
#define CHAN_SWITCH_MODE_ALLOW_TX 0
#define CHAN_SWITCH_MODE_BLOCK_TX 1
@@ -2467,6 +2503,7 @@
#define EHT_OPER_DEFAULT_PE_DURATION BIT(2)
#define EHT_OPER_GROUP_ADDR_BU_INDICATION_LIMIT BIT(3)
#define EHT_OPER_GROUP_ADDR_BU_INDICATION_EXPONENT (BIT(4) | BIT(5))
+#define EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE 2
/* Control subfield: Channel Width subfield; see Table 9-401b */
#define EHT_OPER_CHANNEL_WIDTH_MASK 0x7
@@ -2785,6 +2822,7 @@
#define FD_CAP_BSS_CHWIDTH_40 1
#define FD_CAP_BSS_CHWIDTH_80 2
#define FD_CAP_BSS_CHWIDTH_160_80_80 3
+#define FD_CAP_BSS_CHWIDTH_320 4
#define FD_CAP_BSS_CHWIDTH_SHIFT 2
#define FD_CAP_NSS_1 0
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index f972061..6c25816 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -2,7 +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.
+ * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -894,6 +894,11 @@
* latest several instances of roam information cached in the driver.
* The command is only used for STA mode. The attributes used with this
* command are defined in enum qca_wlan_vendor_attr_roam_cached_stats.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE: This vendor subcommand is used to
+ * configure and fetch the state information of the MLO links affiliated
+ * with the STA interface. The attributes used with this command are
+ * defined in enum qca_wlan_vendor_attr_mlo_link_state.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -1104,6 +1109,7 @@
QCA_NL80211_VENDOR_SUBCMD_DOZED_AP = 224,
QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE = 225,
QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS = 226,
+ QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE = 227,
};
/* Compatibility defines for previously used subcmd names.
@@ -1146,7 +1152,7 @@
* use QCA_WLAN_VENDOR_ATTR_SETBAND_MASK instead.
*/
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
- /* Dummy (NOP) attribute for 64 bit padding */
+ /* Attribute used for padding for 64-bit alignment */
QCA_WLAN_VENDOR_ATTR_PAD = 13,
/* Unique FTM session cookie (Unsigned 64 bit). Specified in
* QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. Reported in
@@ -1376,6 +1382,9 @@
*
* @QCA_ROAM_REASON_BT_ACTIVITY: Roam triggered due to Bluetooth connection is
* established when the station is connected in the 2.4 GHz band.
+ *
+ * @QCA_ROAM_REASON_STA_KICKOUT: Roam triggered due to continuous TX Data frame
+ * failures to the connected AP.
*/
enum qca_roam_reason {
QCA_ROAM_REASON_UNKNOWN,
@@ -1393,6 +1402,7 @@
QCA_ROAM_REASON_PERIODIC_TIMER,
QCA_ROAM_REASON_BACKGROUND_SCAN,
QCA_ROAM_REASON_BT_ACTIVITY,
+ QCA_ROAM_REASON_STA_KICKOUT,
};
enum qca_wlan_vendor_attr_roam_auth {
@@ -2021,6 +2031,8 @@
* This attribute is used to provide TSF sync interval and only applicable when
* TSF command is %QCA_TSF_SYNC_START. If this attribute is not provided, the
* driver will use the default value. Time unit is in milliseconds.
+ * @QCA_WLAN_VENDOR_ATTR_TSF_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_vendor_attr_tsf_cmd {
QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0,
@@ -2028,6 +2040,7 @@
QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE,
QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE,
QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL,
+ QCA_WLAN_VENDOR_ATTR_TSF_PAD,
QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_TSF_MAX =
QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1
@@ -2202,6 +2215,8 @@
* qca_wlan_vendor_scan_priority. This is an optional attribute.
* If this attribute is not configured, the driver shall use
* QCA_WLAN_VENDOR_SCAN_PRIORITY_HIGH as the priority of vendor scan.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -2218,6 +2233,7 @@
QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12,
QCA_WLAN_VENDOR_ATTR_SCAN_PRIORITY = 13,
+ QCA_WLAN_VENDOR_ATTR_SCAN_PAD = 14,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -2609,12 +2625,8 @@
* state, it should not exceed the negotiated channel width. If it is
* configured when STA is in disconnected state, the configured value
* will take effect for the next immediate connection.
- * Possible values are:
- * NL80211_CHAN_WIDTH_20
- * NL80211_CHAN_WIDTH_40
- * NL80211_CHAN_WIDTH_80
- * NL80211_CHAN_WIDTH_80P80
- * NL80211_CHAN_WIDTH_160
+ *
+ * This uses values defined in enum nl80211_chan_width.
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH = 63,
@@ -3432,6 +3444,8 @@
* timestamp and calculate transfer delay for the message.
* @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME: u32
* Real period for this measurement, unit in us.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PAD: Attribute used for padding for
+ * 64-bit alignment.
*/
enum qca_wlan_vendor_attr_ll_stats_ext {
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0,
@@ -3527,6 +3541,7 @@
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME,
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PAD,
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX =
@@ -3812,7 +3827,8 @@
* @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by
* initiator. Not always provided.
* See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
- * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_wlan_vendor_attr_ftm_meas {
QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID,
@@ -4360,6 +4376,13 @@
* after STA has indicated power save exit by QoS Null Data frame.
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR = 89,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PAD = 90,
+
+ /* Signed 32 bit value. It represents the noise floor calibration value.
+ * Possible values are -120~-50 dBm.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL = 90,
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
@@ -5839,6 +5862,9 @@
*/
QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_DENYLISTED_BSSID = 46,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_PAD = 47,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX =
@@ -7029,6 +7055,8 @@
* gain changes.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_RECAPTURE = 31,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PAD = 32,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@@ -7061,6 +7089,8 @@
* mismatches in search fft report. u64 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH = 5,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_PAD = 6,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX =
@@ -9392,12 +9422,15 @@
* @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS: Time stamp of the host
* driver for the last received RSSI. Unsigned 64 bit number containing
* nanoseconds from the boottime.
+ * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_PAD: Attribute used for padding for
+ * 64-bit alignment.
*/
enum qca_wlan_vendor_bss_filter_sta_stats {
QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_INVALID = 0,
QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC = 1,
QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI = 2,
QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS = 3,
+ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_PAD = 4,
/* keep last */
QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST,
@@ -9688,6 +9721,9 @@
* start. The default value in the firmware is 0.
* This parameter is used for
* 1. TWT SET Request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -9724,6 +9760,8 @@
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE = 25,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT = 26,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PAD = 27,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
@@ -9897,6 +9935,8 @@
* If provided, this attribute will override
* QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME. The units are in microseconds.
*
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_wlan_vendor_attr_twt_nudge {
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_INVALID = 0,
@@ -9906,6 +9946,7 @@
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,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_PAD = 7,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST,
@@ -10407,6 +10448,9 @@
* to userspace along with QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG as an
* asynchronous event when the driver is configured to send CFR data using
* netlink events with %QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_wlan_vendor_peer_cfr_capture_attr {
QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0,
@@ -10438,6 +10482,7 @@
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE = 26,
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID = 27,
QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA = 28,
+ QCA_WLAN_VENDOR_ATTR_PEER_CFR_PAD = 29,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST,
@@ -10730,6 +10775,8 @@
* containing buffer of statistics to send to application layer entity.
* @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE: Unsigned 64-bit attribute
* representing a cookie for peer unique session.
+ * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PAD: Attribute used for padding for
+ * 64-bit alignment.
*/
enum qca_wlan_vendor_attr_peer_stats_cache_params {
QCA_WLAN_VENDOR_ATTR_PEER_STATS_INVALID = 0,
@@ -10738,6 +10785,7 @@
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC = 2,
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA = 3,
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE = 4,
+ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PAD = 5,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST,
@@ -11016,6 +11064,8 @@
* reported.
*/
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME = 13,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAD = 14,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST,
@@ -11559,6 +11609,9 @@
* 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.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PAD: Attribute used for padding for
+ * 64-bit alignment.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -11614,6 +11667,7 @@
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,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PAD = 53,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
@@ -12337,6 +12391,8 @@
* or radar detection.
* @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED: NLA_FLAG attribute.
* This flag indicates radar signal has been detected.
+ * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_PAD: Attribute used for padding for
+ * 64-bit alignment.
*/
enum qca_wlan_vendor_attr_radar_history {
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_INVALID = 0,
@@ -12345,6 +12401,7 @@
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_FREQ = 2,
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_TIMESTAMP = 3,
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED = 4,
+ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_PAD = 5,
/* keep last */
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_LAST,
@@ -12360,13 +12417,19 @@
* command it clears MCC quota setting and restores adaptive scheduling.
* @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED: Channel time quota is fixed and
* will not be changed.
+ * This quota type is present in command/event.
* @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_DYNAMIC: Channel time quota is dynamic
* and the target may change the quota based on the data activity.
+ * This quota type is only present in event.
+ * @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY: Channel time quota is optimized
+ * by the target for low latency.
+ * This quota type is only present in command.
*/
enum qca_wlan_vendor_mcc_quota_type {
QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR = 0,
QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED = 1,
QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_DYNAMIC = 2,
+ QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY = 3,
};
/**
@@ -12403,6 +12466,15 @@
* configurations are applied. This is required in a command only. Only one
* interface index may be specified. If not specified, the configuration is
* rejected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LOW_LATENCY_MODE_ENABLE
+ * 8-bit unsigned value to enable/disable Multi-Channel Concurrency
+ * low latency mode. The firmware will do optimization for low
+ * latency in Multi-Channel concurrency state if enabled. And all existing
+ * user quota setting will be overwritten by the target.
+ * 0 - disable(default), 1 - enable.
+ * It is only present in a command with quota type of
+ * QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY.
*/
enum qca_wlan_vendor_attr_mcc_quota {
QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_INVALID = 0,
@@ -12411,6 +12483,7 @@
QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ = 3,
QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE = 4,
QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX = 5,
+ QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LOW_LATENCY_MODE_ENABLE = 6,
/* keep last */
QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LAST,
@@ -12490,6 +12563,44 @@
};
/**
+ * enum qca_wlan_roam_stats_scan_type - Roam scan type define.
+ * These values are used by the attribute
+ * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE.
+ *
+ * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL: Partial channel scan
+ * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL: Full channel scan
+ * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN: No roam scan was triggered.
+ * This is generally used in BTM events to indicate BTM frame exchange logs.
+ * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ: Higher band roam scan
+ * from 2.4 GHz to 5 GHz or 6 GHz
+ * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ: Higher band roam scan from
+ * 5 GHz to 6 GHz
+ */
+enum qca_wlan_roam_stats_scan_type {
+ QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL = 0,
+ QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL = 1,
+ QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN = 2,
+ QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ = 3,
+ QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ = 4,
+};
+
+/**
+ * enum qca_wlan_roam_stats_scan_dwell_type - Roam scan dwell type.
+ * These values are used by the attribute
+ * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE.
+ *
+ * @QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED: Target did not specify the
+ * detailed roam scan type.
+ * @QCA_WLAN_ROAM_STATS_DWELL_ACTIVE_TYPE: Active scan during roam.
+ * @QCA_WLAN_ROAM_STATS_DWELL_PASSIVE_TYPE: Passive scan during roam.
+ */
+enum qca_wlan_roam_stats_scan_dwell_type {
+ QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED = 0,
+ QCA_WLAN_ROAM_STATS_DWELL_TYPE_ACTIVE = 1,
+ QCA_WLAN_ROAM_STATS_DWELL_TYPE_PASSIVE = 2,
+};
+
+/**
* enum qca_wlan_vendor_attr_roam_stats_scan_chan_info - Attributes used inside
* the %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO nested attribute.
*/
@@ -12499,7 +12610,7 @@
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHANNEL_FREQ = 1,
/* 8-bit unsigned value to indicate channel scan type for each
- * roam scan channel. 0-passive, 1-active.
+ * roam scan channel, values in qca_wlan_roam_stats_scan_dwell_type.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE = 2,
/* 32-bit unsigned value to indicate maximum scan time in milliseconds
@@ -12571,6 +12682,8 @@
* from system boot.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_TIMESTAMP = 3,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_PAD = 4,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO_AFTER_LAST,
@@ -12622,11 +12735,11 @@
* roaming trigger by beacon miss.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BMISS_QOS_NULL_SUCCESS = 7,
- /* 8-bit unsigned value to indicate connected AP RSSI in dBm
+ /* 8-bit signed value to indicate connected AP RSSI in dBm
* for trigger reason of poor RSSI.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_CURRENT_RSSI = 8,
- /* 8-bit unsigned value to indicate RSSI threshold value in dBm
+ /* 8-bit signed value to indicate RSSI threshold value in dBm
* for trigger reason of poor RSSI.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD = 9,
@@ -12635,11 +12748,11 @@
* 1 - bad link speed.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS = 10,
- /* 8-bit unsigned value to indicate connected AP RSSI in dBm
+ /* 8-bit signed value to indicate connected AP RSSI in dBm
* for trigger reason of better RSSI.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_CURRENT_RSSI = 11,
- /* 8-bit unsigned value to indicate RSSI threshold value in dBm
+ /* 8-bit signed value to indicate RSSI threshold value in dBm
* for trigger reason of better RSSI.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD = 12,
@@ -12711,15 +12824,15 @@
* reason of periodic timer.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PERIODIC_TIMER_MS = 28,
- /* 8-bit unsigned value to indicate connected AP RSSI in dBm for
+ /* 8-bit signed value to indicate connected AP RSSI in dBm for
* trigger reason of background scan.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI = 29,
- /* 8-bit unsigned value to indicate data RSSI in dBm for trigger reason
+ /* 8-bit signed value to indicate data RSSI in dBm for trigger reason
* of background scan.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI = 30,
- /* 8-bit unsigned value to indicate data RSSI threshold in dBm
+ /* 8-bit signed value to indicate data RSSI threshold in dBm
* for trigger reason of background scan.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_THRESH = 31,
@@ -12736,11 +12849,11 @@
* values in enum qca_wlan_roam_stats_abort_reason.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON = 34,
- /* 8-bit unsigned value to indicate data RSSI in dBm when aborting the
+ /* 8-bit signed value to indicate data RSSI in dBm when aborting the
* roam scan.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI = 35,
- /* 8-bit unsigned value to indicate data RSSI threshold in dBm when
+ /* 8-bit signed value to indicate data RSSI threshold in dBm when
* aborting the roam scan.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI_THRESHOLD = 36,
@@ -12750,7 +12863,7 @@
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RX_LINKSPEED_STATUS = 37,
/* 8-bit unsigned value to indicate roaming scan type.
- * 0 - Partial roam scan, 1 - Full roam scan
+ * One of the values in enum qca_wlan_roam_stats_scan_type.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE = 38,
/* 8-bit unsigned value to indicate roaming result, used in STA mode
@@ -12780,6 +12893,8 @@
* this attribute.
*/
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO = 43,
+ /* Attribute used for padding for 64-bit alignment */
+ QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PAD = 44,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ROAM_STATS_AFTER_LAST,
@@ -13696,6 +13811,9 @@
* greater than the maximum size, it will be truncated and leaving only
* the first 1152 bytes.
* This attribute is mandatory.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_PAD: Attribute used for
+ * padding for 64-bit alignment
*/
enum qca_wlan_vendor_attr_coap_offload_cache_info {
QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_INVALID = 0,
@@ -13703,6 +13821,7 @@
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,
+ QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_PAD = 5,
/* keep last */
QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_AFTER_LAST,
@@ -14791,6 +14910,9 @@
* @QCA_WLAN_VENDOR_ATTR_DOZED_AP_BI_MULTIPLIER: u16 attribute.
* Used with event to inform the periodicity of beacon transmission that would
* be skipped at all TBTTs in between.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DOZED_AP_PAD: Attribute used for padding for 64-bit
+ * alignment.
*/
enum qca_wlan_vendor_attr_dozed_ap {
QCA_WLAN_VENDOR_ATTR_DOZED_AP_INVALID = 0,
@@ -14798,6 +14920,7 @@
QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE = 2,
QCA_WLAN_VENDOR_ATTR_DOZED_AP_NEXT_TSF = 3,
QCA_WLAN_VENDOR_ATTR_DOZED_AP_BI_MULTIPLIER = 4,
+ QCA_WLAN_VENDOR_ATTR_DOZED_AP_PAD = 5,
/* Keep last */
QCA_WLAN_VENDOR_ATTR_DOZED_AP_AFTER_LAST,
@@ -14840,4 +14963,158 @@
QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_link_state_op_types - Defines different types of
+ * operations for which %QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE can be used.
+ * Will be used with %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE attribute.
+ *
+ * @QCA_WLAN_VENDOR_LINK_STATE_OP_GET - Get the MLO links state information.
+ * @QCA_WLAN_VENDOR_LINK_STATE_OP_SET - Set the MLO links state information.
+ */
+enum qca_wlan_vendor_link_state_op_types {
+ QCA_WLAN_VENDOR_LINK_STATE_OP_GET = 0,
+ QCA_WLAN_VENDOR_LINK_STATE_OP_SET = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_link_state_control_modes - Represents the types of MLO
+ * links state control modes. This enum is used by
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE attribute.
+ *
+ * @QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT: MLO links state controlled
+ * by the driver.
+ * @QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER: MLO links state controlled by
+ * user space.
+ * @QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED: User space provides the
+ * desired number of MLO links to operate in active state at any given time.
+ * The driver will choose which MLO links should operate in the active state.
+ * See enum qca_wlan_vendor_link_state for active state definition.
+ */
+enum qca_wlan_vendor_link_state_control_modes {
+ QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT = 0,
+ QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER = 1,
+ QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_link_state_operation_modes - Represents the types of MLO
+ * links state operation modes. This enum is used by
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE attribute.
+ *
+ * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT: In the default operation
+ * mode, the driver selects the operating mode of the links, without any
+ * guidance from the user space.
+ * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_LATENCY: In the low latency
+ * operation mode the driver should select MLO links that will achieve low
+ * latency.
+ * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_HIGH_THROUGHPUT: In the high
+ * throughput operation mode the driver should select MLO links that will
+ * achieve higher throughput.
+ * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_POWER: In the low power
+ * operation mode the driver should select MLO links that will achieve low
+ * power.
+ */
+enum qca_wlan_vendor_link_state_operation_modes {
+ QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT = 0,
+ QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_LATENCY = 1,
+ QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_HIGH_THROUGHPUT = 2,
+ QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_POWER = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_link_state - Represents the possible link states of an
+ * MLO link.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_INACTIVE: In this state, the link will not
+ * be used for data transmission but it can have TIDs mapped to it. It will be
+ * in doze state always and does not monitor the beacons.
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_ACTIVE: In this state, the link will be
+ * used for data TX/RX and monitors the beacons to check TIM bit indication.
+ * It may enter doze state and comes out based on the transmit data traffic and
+ * TIM bit indication in the beacon.
+ */
+enum qca_wlan_vendor_link_state {
+ QCA_WLAN_VENDOR_LINK_STATE_INACTIVE = 0,
+ QCA_WLAN_VENDOR_LINK_STATE_ACTIVE = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_link_state_config - Definition of attributes used
+ * inside nested attribute %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID: u8 attribute, link ID of the
+ * MLO link.
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE: u32 attribute. See
+ * enum qca_wlan_vendor_link_state for possible MLO link states.
+ */
+
+enum qca_wlan_vendor_attr_link_state_config {
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE = 2,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_mlo_link_state - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE: u32 attribute. Indicates the type
+ * of the operation %QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE intended for.
+ * Required only in a command. Possible values for this attribute are defined in
+ * enum qca_wlan_vendor_link_state_op_types.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE: u32 attribute. Indicates MLO
+ * links control mode type. Optional attribute in a command when
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_OP_SET. Required attribute in a response when
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_OP_GET.
+ * See enum qca_wlan_vendor_link_state_control_modes for possible control modes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG: Array of nested attributes.
+ * Indicates the state of the each MLO link affiliated with the interface.
+ * Required attribute in a command when %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE
+ * is set to %QCA_WLAN_VENDOR_LINK_STATE_OP_SET and
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER. Required attribute in a
+ * response when %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_OP_GET.
+ * See enum qca_wlan_vendor_attr_link_state_config for the nested attributes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS: u8 attribute.
+ * Represents the number of active state links. See enum
+ * qca_wlan_vendor_link_state for active state definition.
+ * Required attribute in a command when %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE
+ * is set to %QCA_WLAN_VENDOR_LINK_STATE_OP_SET and
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE: u32 attribute. Indicates MLO
+ * links operation mode type. Optional attribute in a command when
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_OP_SET. Required attribute in a response when
+ * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to
+ * %QCA_WLAN_VENDOR_LINK_STATE_OP_GET.
+ * See enum qca_wlan_vendor_link_state_operation_modes for possible operation
+ * modes.
+ */
+enum qca_wlan_vendor_attr_mlo_link_state {
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE = 2,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG = 3,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS = 4,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX =
+ QCA_WLAN_VENDOR_ATTR_LINK_STATE_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 4ddfe07..1477ecc 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -41,23 +41,12 @@
#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
#define HOSTAPD_CHAN_DFS_MASK 0x00000300
-#define HOSTAPD_CHAN_VHT_10_70 0x00000800
-#define HOSTAPD_CHAN_VHT_30_50 0x00001000
-#define HOSTAPD_CHAN_VHT_50_30 0x00002000
-#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+#define HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL 0x00000800
+#define HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL 0x00001000
#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
-#define HOSTAPD_CHAN_VHT_10_150 0x00100000
-#define HOSTAPD_CHAN_VHT_30_130 0x00200000
-#define HOSTAPD_CHAN_VHT_50_110 0x00400000
-#define HOSTAPD_CHAN_VHT_70_90 0x00800000
-#define HOSTAPD_CHAN_VHT_90_70 0x01000000
-#define HOSTAPD_CHAN_VHT_110_50 0x02000000
-#define HOSTAPD_CHAN_VHT_130_30 0x04000000
-#define HOSTAPD_CHAN_VHT_150_10 0x08000000
-
/* Allowed bandwidth mask */
enum hostapd_chan_width_attr {
HOSTAPD_CHAN_WIDTH_10 = BIT(0),
@@ -181,6 +170,11 @@
* wmm_rules - WMM regulatory rules
*/
struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM];
+
+ /**
+ * punct_bitmap - RU puncturing bitmap
+ */
+ u16 punct_bitmap;
};
#define HE_MAC_CAPAB_0 0
@@ -1731,6 +1725,14 @@
* ema - Enhanced MBSSID advertisements support.
*/
bool ema;
+
+ /**
+ * punct_bitmap - Preamble puncturing bitmap
+ * Each bit corresponds to a 20 MHz subchannel, the lowest bit for the
+ * channel with the lowest frequency. A bit set to 1 indicates that the
+ * subchannel is punctured, otherwise active.
+ */
+ u16 punct_bitmap;
};
struct wpa_driver_mesh_bss_params {
@@ -2324,6 +2326,13 @@
struct hostapd_data;
+enum guard_interval {
+ GUARD_INTERVAL_0_4 = 1,
+ GUARD_INTERVAL_0_8 = 2,
+ GUARD_INTERVAL_1_6 = 3,
+ GUARD_INTERVAL_3_2 = 4,
+};
+
#define STA_DRV_DATA_TX_MCS BIT(0)
#define STA_DRV_DATA_RX_MCS BIT(1)
#define STA_DRV_DATA_TX_VHT_MCS BIT(2)
@@ -2338,6 +2347,10 @@
#define STA_DRV_DATA_RX_HE_MCS BIT(11)
#define STA_DRV_DATA_TX_HE_NSS BIT(12)
#define STA_DRV_DATA_RX_HE_NSS BIT(13)
+#define STA_DRV_DATA_TX_HE_DCM BIT(14)
+#define STA_DRV_DATA_RX_HE_DCM BIT(15)
+#define STA_DRV_DATA_TX_HE_GI BIT(16)
+#define STA_DRV_DATA_RX_HE_GI BIT(17)
struct hostap_sta_driver_data {
unsigned long rx_packets, tx_packets;
@@ -2375,6 +2388,8 @@
s8 avg_signal; /* dBm */
s8 avg_beacon_signal; /* dBm */
s8 avg_ack_signal; /* dBm */
+ enum guard_interval rx_guard_interval, tx_guard_interval;
+ u8 rx_dcm, tx_dcm;
};
struct hostapd_sta_add_params {
@@ -2408,6 +2423,10 @@
const u8 *supp_oper_classes;
size_t supp_oper_classes_len;
int support_p2p_ps;
+
+ bool mld_link_sta;
+ s8 mld_link_id;
+ const u8 *mld_link_addr;
};
struct mac_address {
@@ -2582,6 +2601,7 @@
* @beacon_after: Next beacon/probe resp/asooc resp info
* @counter_offset_beacon: Offset to the count field in beacon's tail
* @counter_offset_presp: Offset to the count field in probe resp.
+ * @punct_bitmap - Preamble puncturing bitmap
*/
struct csa_settings {
u8 cs_count;
@@ -2593,6 +2613,8 @@
u16 counter_offset_beacon[2];
u16 counter_offset_presp[2];
+
+ u16 punct_bitmap;
};
/**
@@ -2652,6 +2674,7 @@
enum drv_br_port_attr {
DRV_BR_PORT_ATTR_PROXYARP,
DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+ DRV_BR_PORT_ATTR_MCAST2UCAST,
};
enum drv_br_net_param {
@@ -2740,6 +2763,7 @@
* the real status code for failures. Used only for the request interface
* from user space to the driver.
* @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE).
+ * @mld_addr: AP's MLD address or %NULL if MLO is not used
*/
struct external_auth {
enum {
@@ -2752,6 +2776,7 @@
unsigned int key_mgmt_suite;
u16 status;
const u8 *pmkid;
+ const u8 *mld_addr;
};
#define WPAS_MAX_PASN_PEERS 10
@@ -4516,6 +4541,16 @@
int (*set_replay_protect)(void *priv, bool enabled, u32 window);
/**
+ * set_offload - Set MACsec hardware offload
+ * @priv: Private driver interface data
+ * @offload: 0 = MACSEC_OFFLOAD_OFF
+ * 1 = MACSEC_OFFLOAD_PHY
+ * 2 = MACSEC_OFFLOAD_MAC
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*set_offload)(void *priv, u8 offload);
+
+ /**
* set_current_cipher_suite - Set current cipher suite
* @priv: Private driver interface data
* @cs: EUI64 identifier
@@ -4957,6 +4992,15 @@
int (*get_sta_mlo_info)(void *priv,
struct driver_sta_mlo_info *mlo_info);
+ /**
+ * link_add - Add a link to the AP MLD interface
+ * @priv: Private driver interface data
+ * @link_id: The link ID
+ * @addr: The MAC address to use for the link
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*link_add)(void *priv, u8 link_id, const u8 *addr);
+
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
const u8 *match, size_t match_len,
@@ -6097,6 +6141,12 @@
* ssi_signal - Signal strength in dBm (or 0 if not available)
*/
int ssi_signal;
+
+ /**
+ * link_id - MLO link on which the frame was received or -1 for
+ * non MLD.
+ */
+ int link_id;
} rx_mgmt;
/**
@@ -6197,6 +6247,7 @@
const u8 *data;
size_t data_len;
enum frame_encryption encrypted;
+ int link_id;
} eapol_rx;
/**
@@ -6290,6 +6341,7 @@
* @cf1: Center frequency 1
* @cf2: Center frequency 2
* @link_id: Link ID of the MLO link
+ * @punct_bitmap: Puncturing bitmap
*/
struct ch_switch {
int freq;
@@ -6299,6 +6351,7 @@
int cf1;
int cf2;
int link_id;
+ u16 punct_bitmap;
} ch_switch;
/**
@@ -6551,12 +6604,14 @@
event.eapol_rx.data = data;
event.eapol_rx.data_len = data_len;
event.eapol_rx.encrypted = FRAME_ENCRYPTION_UNKNOWN;
+ event.eapol_rx.link_id = -1;
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)
+ size_t data_len,
+ enum frame_encryption encrypted,
+ int link_id)
{
union wpa_event_data event;
os_memset(&event, 0, sizeof(event));
@@ -6564,6 +6619,7 @@
event.eapol_rx.data = data;
event.eapol_rx.data_len = data_len;
event.eapol_rx.encrypted = encrypted;
+ event.eapol_rx.link_id = link_id;
wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
}
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index b609bbf..c79e873 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -32,6 +32,10 @@
#define UNUSED_SCI 0xffffffffffffffff
+#if LIBNL_VER_NUM >= LIBNL_VER(3, 6)
+#define LIBNL_HAS_OFFLOAD
+#endif
+
struct cb_arg {
struct macsec_drv_data *drv;
u32 *pn;
@@ -73,6 +77,11 @@
bool replay_protect;
bool replay_protect_set;
+#ifdef LIBNL_HAS_OFFLOAD
+ enum macsec_offload offload;
+ bool offload_set;
+#endif /* LIBNL_HAS_OFFLOAD */
+
u32 replay_window;
u8 encoding_sa;
@@ -228,6 +237,15 @@
drv->replay_window);
}
+#ifdef LIBNL_HAS_OFFLOAD
+ if (drv->offload_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit offload=%d",
+ drv->ifname, drv->offload);
+ rtnl_link_macsec_set_offload(drv->link, drv->offload);
+ }
+#endif /* LIBNL_HAS_OFFLOAD */
+
if (drv->encoding_sa_set) {
wpa_printf(MSG_DEBUG, DRV_PREFIX
"%s: try_commit encoding_sa=%d",
@@ -456,6 +474,36 @@
/**
+ * macsec_drv_set_offload - Set offload status
+ * @priv: Private driver interface data
+ * @offload: 0 = MACSEC_OFFLOAD_OFF
+ * 1 = MACSEC_OFFLOAD_PHY
+ * 2 = MACSEC_OFFLOAD_MAC
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_offload(void *priv, u8 offload)
+{
+#ifdef LIBNL_HAS_OFFLOAD
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %02" PRIx8, __func__, offload);
+
+ drv->offload_set = true;
+ drv->offload = offload;
+
+ return try_commit(drv);
+#else /* LIBNL_HAS_OFFLOAD */
+ if (offload == 0)
+ return 0;
+ wpa_printf(MSG_INFO,
+ "%s: libnl version does not include support for MACsec offload",
+ __func__);
+ return -1;
+#endif /* LIBNL_HAS_OFFLOAD */
+}
+
+
+/**
* macsec_drv_set_current_cipher_suite - Set current cipher suite
* @priv: Private driver interface data
* @cs: EUI64 identifier
@@ -1648,6 +1696,7 @@
.enable_protect_frames = macsec_drv_enable_protect_frames,
.enable_encrypt = macsec_drv_enable_encrypt,
.set_replay_protect = macsec_drv_set_replay_protect,
+ .set_offload = macsec_drv_set_offload,
.set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
.enable_controlled_port = macsec_drv_enable_controlled_port,
.get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c7e9bfe..cc87e72 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -175,6 +175,8 @@
const u16 *csa_offs, size_t csa_offs_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report);
+static int nl80211_put_freq_params(struct nl_msg *msg,
+ const struct hostapd_freq_params *freq);
#define IFIDX_ANY -1
@@ -277,7 +279,7 @@
drv->associated = 0;
os_memset(&drv->sta_mlo_info, 0, sizeof(drv->sta_mlo_info));
os_memset(drv->bssid, 0, ETH_ALEN);
- drv->first_bss->freq = 0;
+ drv->first_bss->flink->freq = 0;
#ifdef CONFIG_DRIVER_NL80211_QCA
os_free(drv->pending_roam_data);
drv->pending_roam_data = NULL;
@@ -915,7 +917,7 @@
dl_list_init(&w->drvs);
/* Beacon frames not supported in IEEE 802.11ad */
- if (ieee80211_freq_to_chan(bss->freq, &channel) !=
+ if (ieee80211_freq_to_chan(bss->flink->freq, &channel) !=
HOSTAPD_MODE_IEEE80211AD) {
w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!w->nl_cb) {
@@ -1904,6 +1906,16 @@
return -ENOMEM;
nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) {
+ /* put wiphy idx to get the interface specific country code
+ * instead of the global one. */
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
alpha2[0] = '\0';
ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2,
NULL, NULL);
@@ -2236,6 +2248,7 @@
{
struct wpa_driver_nl80211_data *drv;
struct i802_bss *bss;
+ unsigned int i;
if (global_priv == NULL)
return NULL;
@@ -2314,6 +2327,17 @@
drv->in_interface_list = 1;
}
+ /*
+ * Set the default link to be the first one, and set its address to that
+ * of the interface.
+ */
+ bss->flink = &bss->links[0];
+ bss->n_links = 1;
+ os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
+ bss->links[i].link_id = NL80211_DRV_LINK_ID_NA;
+
return bss;
failed:
@@ -2981,21 +3005,50 @@
}
-static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
+static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss,
+ struct i802_link *link)
{
struct nl_msg *msg;
struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (!link->beacon_set)
+ return 0;
+
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
- bss->beacon_set = 0;
- bss->freq = 0;
+ link->beacon_set = 0;
+ link->freq = 0;
+
nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
+ if (!msg)
+ return -ENOBUFS;
+
+ if (link->link_id != NL80211_DRV_LINK_ID_NA) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLD: stop beaconing on link=%u",
+ link->link_id);
+
+ if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
+ link->link_id)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ }
+
return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
}
+static void wpa_driver_nl80211_del_beacon_all(struct i802_bss *bss)
+{
+ unsigned int i;
+
+ for (i = 0; i < bss->n_links; i++)
+ wpa_driver_nl80211_del_beacon(bss, &bss->links[i]);
+}
+
+
/**
* wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
* @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
@@ -3045,7 +3098,7 @@
nl80211_remove_monitor_interface(drv);
if (is_ap_interface(drv->nlmode))
- wpa_driver_nl80211_del_beacon(bss);
+ wpa_driver_nl80211_del_beacon_all(bss);
if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock);
@@ -4222,10 +4275,10 @@
if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
if (freq == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
- bss->freq);
- freq = bss->freq;
+ bss->flink->freq);
+ freq = bss->flink->freq;
}
- if ((int) freq == bss->freq)
+ if ((int) freq == bss->flink->freq)
wait_time = 0;
goto send_frame_cmd;
}
@@ -4287,14 +4340,14 @@
}
if (freq == 0) {
wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u",
- bss->freq);
- freq = bss->freq;
+ bss->flink->freq);
+ freq = bss->flink->freq;
}
if (drv->use_monitor && is_ap_interface(drv->nlmode)) {
wpa_printf(MSG_DEBUG,
"nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
- freq, bss->freq);
+ freq, bss->flink->freq);
return nl80211_send_monitor(drv, data, data_len, encrypt,
noack);
}
@@ -4807,7 +4860,7 @@
struct wpa_driver_mesh_bss_params mesh_params;
#endif /* CONFIG_MESH */
- beacon_set = params->reenable ? 0 : bss->beacon_set;
+ beacon_set = params->reenable ? 0 : bss->flink->beacon_set;
wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
beacon_set);
@@ -5061,6 +5114,9 @@
nla_nest_end(msg, spr);
}
+ if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
+ goto fail;
+
if (params->freq && params->freq->he_enabled) {
struct nlattr *bss_color;
@@ -5102,22 +5158,30 @@
goto fail;
#endif /* CONFIG_FILS */
+ if (params->punct_bitmap) {
+ wpa_printf(MSG_DEBUG, "nl80211: Puncturing bitmap=0x%04x",
+ params->punct_bitmap);
+ if (nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
+ params->punct_bitmap))
+ goto fail;
+ }
+
ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
ret, strerror(-ret));
} else {
- bss->beacon_set = 1;
+ bss->flink->beacon_set = 1;
nl80211_set_bss(bss, params->cts_protect, params->preamble,
params->short_slot_time, params->ht_opmode,
params->isolate, params->basic_rates);
nl80211_set_multicast_to_unicast(bss,
params->multicast_to_unicast);
if (beacon_set && params->freq &&
- params->freq->bandwidth != bss->bandwidth) {
+ params->freq->bandwidth != bss->flink->bandwidth) {
wpa_printf(MSG_DEBUG,
"nl80211: Update BSS %s bandwidth: %d -> %d",
- bss->ifname, bss->bandwidth,
+ bss->ifname, bss->flink->bandwidth,
params->freq->bandwidth);
ret = nl80211_set_channel(bss, params->freq, 1);
if (ret) {
@@ -5127,7 +5191,7 @@
} else {
wpa_printf(MSG_DEBUG,
"nl80211: Frequency set succeeded for ht2040 coex");
- bss->bandwidth = params->freq->bandwidth;
+ bss->flink->bandwidth = params->freq->bandwidth;
}
} else if (!beacon_set && params->freq) {
/*
@@ -5135,7 +5199,7 @@
* mode only at the point when beaconing is started, so
* set the initial value here.
*/
- bss->bandwidth = params->freq->bandwidth;
+ bss->flink->bandwidth = params->freq->bandwidth;
}
}
@@ -5285,7 +5349,7 @@
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == 0) {
- bss->freq = freq->freq;
+ bss->flink->freq = freq->freq;
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
@@ -5352,16 +5416,29 @@
struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
int ret = -ENOBUFS;
+ u8 cmd;
+ const char *cmd_string;
if ((params->flags & WPA_STA_TDLS_PEER) &&
!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
return -EOPNOTSUPP;
+ if (params->mld_link_sta) {
+ cmd = params->set ? NL80211_CMD_MODIFY_LINK_STA :
+ NL80211_CMD_ADD_LINK_STA;
+ cmd_string = params->set ? "NL80211_CMD_MODIFY_LINK_STA" :
+ "NL80211_CMD_ADD_LINK_STA";
+ } else {
+ cmd = params->set ? NL80211_CMD_SET_STATION :
+ NL80211_CMD_NEW_STATION;
+ cmd_string = params->set ? "NL80211_CMD_SET_STATION" :
+ "NL80211_CMD_NEW_STATION";
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
- params->set ? "Set" : "Add", MAC2STR(params->addr));
- msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
- NL80211_CMD_NEW_STATION);
- if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+ cmd_string, MAC2STR(params->addr));
+ msg = nl80211_bss_msg(bss, 0, cmd);
+ if (!msg)
goto fail;
/*
@@ -5579,12 +5656,43 @@
nla_nest_end(msg, wme);
}
+ /* In case we are an AP MLD need to always specify the link ID */
+ if (params->mld_link_id >= 0) {
+ wpa_printf(MSG_DEBUG, " * mld_link_id=%d",
+ params->mld_link_id);
+ if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID,
+ params->mld_link_id))
+ goto fail;
+
+ /*
+ * If the link address is specified the station is a non-AP MLD
+ * and thus need to provide the MLD address as the station
+ * address, and the non-AP MLD link address as the link address.
+ */
+ if (params->mld_link_addr) {
+ wpa_printf(MSG_DEBUG, " * mld_link_addr=" MACSTR,
+ MAC2STR(params->mld_link_addr));
+
+ if (nla_put(msg, NL80211_ATTR_MLD_ADDR,
+ ETH_ALEN, params->addr) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
+ params->mld_link_addr))
+ goto fail;
+ } else {
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
+ params->addr))
+ goto fail;
+ }
+ } else {
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+ goto fail;
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
if (ret)
- wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
- "result: %d (%s)", params->set ? "SET" : "NEW", ret,
- strerror(-ret));
+ wpa_printf(MSG_DEBUG, "nl80211: %s result: %d (%s)",
+ cmd_string, ret, strerror(-ret));
if (ret == -EEXIST)
ret = 0;
fail:
@@ -5913,7 +6021,7 @@
nl80211_mgmt_unsubscribe(bss, "AP teardown");
nl80211_put_wiphy_data_ap(bss);
- bss->beacon_set = 0;
+ bss->flink->beacon_set = 0;
}
@@ -6807,6 +6915,10 @@
nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
return -1;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT))
+ return -1;
+
return 0;
}
@@ -7527,6 +7639,8 @@
[NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 },
[NL80211_RATE_INFO_HE_MCS] = { .type = NLA_U8 },
[NL80211_RATE_INFO_HE_NSS] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_HE_GI] = { .type = NLA_U8 },
+ [NL80211_RATE_INFO_HE_DCM] = { .type = NLA_U8 },
};
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
@@ -7650,8 +7764,10 @@
nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
data->flags |= STA_DRV_DATA_TX_VHT_MCS;
}
- if (rate[NL80211_RATE_INFO_SHORT_GI])
+ if (rate[NL80211_RATE_INFO_SHORT_GI]) {
+ data->tx_guard_interval = GUARD_INTERVAL_0_4;
data->flags |= STA_DRV_DATA_TX_SHORT_GI;
+ }
if (rate[NL80211_RATE_INFO_VHT_NSS]) {
data->tx_vht_nss =
nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
@@ -7667,6 +7783,25 @@
nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]);
data->flags |= STA_DRV_DATA_TX_HE_NSS;
}
+ if (rate[NL80211_RATE_INFO_HE_GI]) {
+ switch (nla_get_u8(rate[NL80211_RATE_INFO_HE_GI])) {
+ case NL80211_RATE_INFO_HE_GI_0_8:
+ data->tx_guard_interval = GUARD_INTERVAL_0_8;
+ break;
+ case NL80211_RATE_INFO_HE_GI_1_6:
+ data->tx_guard_interval = GUARD_INTERVAL_1_6;
+ break;
+ case NL80211_RATE_INFO_HE_GI_3_2:
+ data->tx_guard_interval = GUARD_INTERVAL_3_2;
+ break;
+ }
+ data->flags |= STA_DRV_DATA_TX_HE_GI;
+ }
+ if (rate[NL80211_RATE_INFO_HE_DCM]) {
+ data->tx_dcm =
+ nla_get_u8(rate[NL80211_RATE_INFO_HE_DCM]);
+ data->flags |= STA_DRV_DATA_TX_HE_DCM;
+ }
}
if (stats[NL80211_STA_INFO_RX_BITRATE] &&
@@ -7693,8 +7828,10 @@
nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]);
data->flags |= STA_DRV_DATA_RX_VHT_MCS;
}
- if (rate[NL80211_RATE_INFO_SHORT_GI])
+ if (rate[NL80211_RATE_INFO_SHORT_GI]) {
+ data->rx_guard_interval = GUARD_INTERVAL_0_4;
data->flags |= STA_DRV_DATA_RX_SHORT_GI;
+ }
if (rate[NL80211_RATE_INFO_VHT_NSS]) {
data->rx_vht_nss =
nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]);
@@ -7710,6 +7847,25 @@
nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]);
data->flags |= STA_DRV_DATA_RX_HE_NSS;
}
+ if (rate[NL80211_RATE_INFO_HE_GI]) {
+ switch (nla_get_u8(rate[NL80211_RATE_INFO_HE_GI])) {
+ case NL80211_RATE_INFO_HE_GI_0_8:
+ data->rx_guard_interval = GUARD_INTERVAL_0_8;
+ break;
+ case NL80211_RATE_INFO_HE_GI_1_6:
+ data->rx_guard_interval = GUARD_INTERVAL_1_6;
+ break;
+ case NL80211_RATE_INFO_HE_GI_3_2:
+ data->rx_guard_interval = GUARD_INTERVAL_3_2;
+ break;
+ }
+ data->flags |= STA_DRV_DATA_RX_HE_GI;
+ }
+ if (rate[NL80211_RATE_INFO_HE_DCM]) {
+ data->rx_dcm =
+ nla_get_u8(rate[NL80211_RATE_INFO_HE_DCM]);
+ data->flags |= STA_DRV_DATA_RX_HE_DCM;
+ }
}
if (stats[NL80211_STA_INFO_TID_STATS])
@@ -7885,7 +8041,7 @@
struct ieee80211_mgmt mgmt;
u8 channel;
- if (ieee80211_freq_to_chan(bss->freq, &channel) ==
+ if (ieee80211_freq_to_chan(bss->flink->freq, &channel) ==
HOSTAPD_MODE_IEEE80211AD) {
/* Deauthentication is not used in DMG/IEEE 802.11ad;
* disassociate the STA instead. */
@@ -8508,12 +8664,18 @@
if (type == WPA_IF_AP_BSS && setup_ap) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+ unsigned int i;
+
if (new_bss == NULL) {
if (added)
nl80211_remove_iface(drv, ifidx);
return -1;
}
+ /* Initialize here before any failure path */
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
+ new_bss->links[i].link_id = NL80211_DRV_LINK_ID_NA;
+
if (bridge &&
i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
@@ -8537,7 +8699,11 @@
new_bss->ifindex = ifidx;
new_bss->drv = drv;
new_bss->next = drv->first_bss->next;
- new_bss->freq = drv->first_bss->freq;
+ new_bss->flink = &new_bss->links[0];
+ new_bss->n_links = 1;
+ os_memcpy(new_bss->flink->addr, new_bss->addr, ETH_ALEN);
+
+ new_bss->flink->freq = drv->first_bss->flink->freq;
new_bss->ctx = bss_ctx;
new_bss->added_if = added;
drv->first_bss->next = new_bss;
@@ -8629,7 +8795,7 @@
wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
nl80211_teardown_ap(bss);
if (!bss->added_if && !drv->first_bss->next)
- wpa_driver_nl80211_del_beacon(bss);
+ wpa_driver_nl80211_del_beacon_all(bss);
nl80211_destroy_bss(bss);
if (!bss->added_if)
i802_set_iface_flags(bss, 0);
@@ -8744,8 +8910,8 @@
struct ieee80211_hdr *hdr;
int offchanok = 1;
- if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq &&
- bss->beacon_set)
+ if (is_ap_interface(drv->nlmode) && (int) freq == bss->flink->freq &&
+ bss->flink->beacon_set)
offchanok = 0;
wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
@@ -8781,7 +8947,7 @@
modes = nl80211_get_hw_feature_data(bss, &num_modes,
&flags, &dfs_domain);
if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
- ieee80211_is_dfs(bss->freq, modes, num_modes))
+ ieee80211_is_dfs(bss->flink->freq, modes, num_modes))
offchanok = 0;
if (modes) {
for (i = 0; i < num_modes; i++) {
@@ -8795,7 +8961,7 @@
if (is_ap_interface(drv->nlmode) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
- (int) freq == bss->freq || drv->device_ap_sme ||
+ (int) freq == bss->flink->freq || drv->device_ap_sme ||
!drv->use_monitor))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
0, freq, no_cck, offchanok,
@@ -9025,13 +9191,71 @@
}
+static void nl80211_remove_links(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ u8 link_id;
+
+ while (bss->links[0].link_id != NL80211_DRV_LINK_ID_NA) {
+ struct i802_link *link = &bss->links[0];
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLD: remove link_id=%u",
+ link->link_id);
+
+ wpa_driver_nl80211_del_beacon(bss, link);
+
+ link_id = link->link_id;
+
+ /* First remove the link locally */
+ if (bss->n_links == 1) {
+ bss->flink->link_id = NL80211_DRV_LINK_ID_NA;
+ os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN);
+ } else {
+ struct i802_link *other = &bss->links[bss->n_links - 1];
+
+ os_memcpy(link, other, sizeof(*link));
+ other->link_id = NL80211_DRV_LINK_ID_NA;
+ os_memset(other->addr, 0, ETH_ALEN);
+
+ bss->n_links--;
+ }
+
+ /* Remove the link from the kernel */
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_REMOVE_LINK);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR,
+ "nl80211: remove link (%d) failed",
+ link_id);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: remove link (%d) failed. ret=%d (%s)",
+ link_id, ret, strerror(-ret));
+ return;
+ }
+ }
+}
+
+
static int wpa_driver_nl80211_deinit_ap(void *priv)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
+
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon(bss);
+
+ /* Stop beaconing */
+ wpa_driver_nl80211_del_beacon(bss, bss->flink);
+
+ nl80211_remove_links(bss);
/*
* If the P2P GO interface was dynamically added, then it is
@@ -9048,9 +9272,12 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
+
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon(bss);
+
+ wpa_driver_nl80211_del_beacon_all(bss);
+
return 0;
}
@@ -10352,8 +10579,8 @@
bss->ifname,
bss->brname,
MAC2STR(bss->addr),
- bss->freq,
- bss->beacon_set ? "beacon_set=1\n" : "",
+ bss->flink->freq,
+ bss->flink->beacon_set ? "beacon_set=1\n" : "",
bss->added_if_into_bridge ?
"added_if_into_bridge=1\n" : "",
bss->already_in_bridge ? "already_in_bridge=1\n" : "",
@@ -10571,7 +10798,7 @@
int i;
wpa_printf(MSG_DEBUG,
- "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d%s%s%s)",
+ "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x%s%s%s)",
settings->cs_count, settings->block_tx,
settings->freq_params.freq,
settings->freq_params.channel,
@@ -10579,6 +10806,7 @@
settings->freq_params.bandwidth,
settings->freq_params.center_freq1,
settings->freq_params.center_freq2,
+ settings->punct_bitmap,
settings->freq_params.ht_enabled ? " ht" : "",
settings->freq_params.vht_enabled ? " vht" : "",
settings->freq_params.he_enabled ? " he" : "");
@@ -10649,7 +10877,10 @@
settings->cs_count) ||
(ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
(settings->block_tx &&
- nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
+ nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)) ||
+ (settings->punct_bitmap &&
+ nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
+ settings->punct_bitmap)))
goto error;
/* beacon_after params */
@@ -11448,7 +11679,7 @@
goto fail;
}
ret = 0;
- drv->assoc_freq = bss->freq = params->freq.freq;
+ drv->assoc_freq = bss->flink->freq = params->freq.freq;
wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
fail:
@@ -11504,7 +11735,7 @@
} else {
wpa_printf(MSG_DEBUG,
"nl80211: mesh leave request send successfully");
- drv->first_bss->freq = 0;
+ drv->first_bss->flink->freq = 0;
}
if (drv->start_mode_sta &&
@@ -11745,6 +11976,8 @@
return "proxyarp_wifi";
case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
return "hairpin_mode";
+ case DRV_BR_PORT_ATTR_MCAST2UCAST:
+ return "multicast_to_unicast";
}
return NULL;
@@ -13202,6 +13435,77 @@
}
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ unsigned int idx, i;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLD: add link_id=%u, addr=" MACSTR,
+ link_id, MAC2STR(addr));
+
+ if (drv->nlmode != NL80211_IFTYPE_AP) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLD: cannot add link to iftype=%u",
+ drv->nlmode);
+ return -EINVAL;
+ }
+
+ if (bss->n_links >= MAX_NUM_MLD_LINKS) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLD: already have n_links=%zu",
+ bss->n_links);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < bss->n_links; i++) {
+ if (bss->links[i].link_id == link_id &&
+ bss->links[i].beacon_set) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLD: link already set");
+ return -EINVAL;
+ }
+ }
+
+ /* try using the first link entry, assuming it is not beaconing yet */
+ if (bss->n_links == 1 &&
+ bss->flink->link_id == NL80211_DRV_LINK_ID_NA) {
+ if (bss->flink->beacon_set) {
+ wpa_printf(MSG_DEBUG, "nl80211: BSS already beaconing");
+ return -EINVAL;
+ }
+
+ idx = 0;
+ } else {
+ idx = bss->n_links;
+ }
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ADD_LINK);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: add link failed. ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+ }
+
+ bss->links[idx].link_id = link_id;
+ os_memcpy(bss->links[idx].addr, addr, ETH_ALEN);
+
+ bss->n_links = idx + 1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLD: n_links=%zu", bss->n_links);
+ return 0;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int testing_nl80211_register_frame(void *priv, u16 type,
@@ -13394,6 +13698,7 @@
.dpp_listen = nl80211_dpp_listen,
#endif /* CONFIG_DPP */
.get_sta_mlo_info = nl80211_get_sta_mlo_info,
+ .link_add = nl80211_link_add,
#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 694fb1b..bd35e52 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -49,15 +49,31 @@
int wiphy_idx;
};
+#define NL80211_DRV_LINK_ID_NA (-1)
+
+struct i802_link {
+ unsigned int beacon_set:1;
+
+ s8 link_id;
+ int freq;
+ int bandwidth;
+ u8 addr[ETH_ALEN];
+ void *ctx;
+};
+
struct i802_bss {
struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
+
+ size_t n_links;
+ struct i802_link links[MAX_NUM_MLD_LINKS];
+ struct i802_link *flink;
+
int ifindex;
int br_ifindex;
u64 wdev_id;
char ifname[IFNAMSIZ + 1];
char brname[IFNAMSIZ];
- unsigned int beacon_set:1;
unsigned int added_if_into_bridge:1;
unsigned int already_in_bridge:1;
unsigned int added_bridge:1;
@@ -70,8 +86,6 @@
u8 addr[ETH_ALEN];
u8 prev_addr[ETH_ALEN];
- int freq;
- int bandwidth;
int if_dynamic;
void *ctx;
@@ -184,6 +198,7 @@
unsigned int brcm_do_acs:1;
unsigned int uses_6ghz:1;
unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
+ unsigned int puncturing:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 2f3b85a..3152529 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -663,6 +663,9 @@
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP))
info->drv->unsol_bcast_probe_resp = 1;
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_PUNCT))
+ info->drv->puncturing = 1;
+
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT;
@@ -2327,43 +2330,15 @@
for (c = 0; c < mode->num_channels; c++) {
struct hostapd_channel_data *chan = &mode->channels[c];
- if (chan->freq - 10 >= start && chan->freq + 70 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_10_70;
- if (chan->freq - 30 >= start && chan->freq + 50 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+ if (chan->freq - 10 < start || chan->freq + 10 > end)
+ continue;
- if (chan->freq - 50 >= start && chan->freq + 30 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+ if (max_bw >= 80)
+ chan->flag |= HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL;
- if (chan->freq - 70 >= start && chan->freq + 10 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_70_10;
-
- if (max_bw >= 160) {
- if (chan->freq - 10 >= start && chan->freq + 150 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_10_150;
-
- if (chan->freq - 30 >= start && chan->freq + 130 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_30_130;
-
- if (chan->freq - 50 >= start && chan->freq + 110 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_50_110;
-
- if (chan->freq - 70 >= start && chan->freq + 90 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_70_90;
-
- if (chan->freq - 90 >= start && chan->freq + 70 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_90_70;
-
- if (chan->freq - 110 >= start && chan->freq + 50 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_110_50;
-
- if (chan->freq - 130 >= start && chan->freq + 30 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_130_30;
-
- if (chan->freq - 150 >= start && chan->freq + 10 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_150_10;
- }
+ if (max_bw >= 160)
+ chan->flag |= HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL;
}
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 46e4efb..8b0275a 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -183,6 +183,7 @@
C2S(NL80211_CMD_ADD_LINK_STA)
C2S(NL80211_CMD_MODIFY_LINK_STA)
C2S(NL80211_CMD_REMOVE_LINK_STA)
+ C2S(NL80211_CMD_SET_HW_TIMESTAMP)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@@ -326,7 +327,7 @@
}
event.assoc_info.freq = drv->assoc_freq;
- drv->first_bss->freq = drv->assoc_freq;
+ drv->first_bss->flink->freq = drv->assoc_freq;
nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
@@ -851,7 +852,7 @@
}
event.assoc_info.freq = nl80211_get_assoc_freq(drv);
- drv->first_bss->freq = drv->assoc_freq;
+ drv->first_bss->flink->freq = drv->assoc_freq;
if ((!ssid || ssid[1] == 0 || ssid[1] > 32) &&
(ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) {
@@ -993,7 +994,9 @@
struct nlattr *ifindex, struct nlattr *link,
struct nlattr *freq, struct nlattr *type,
struct nlattr *bw, struct nlattr *cf1,
- struct nlattr *cf2, int finished)
+ struct nlattr *cf2,
+ struct nlattr *punct_bitmap,
+ int finished)
{
struct i802_bss *bss;
union wpa_event_data data;
@@ -1048,6 +1051,8 @@
data.ch_switch.freq = nla_get_u32(freq);
data.ch_switch.ht_enabled = ht_enabled;
data.ch_switch.ch_offset = chan_offset;
+ if (punct_bitmap)
+ data.ch_switch.punct_bitmap = (u16) nla_get_u32(punct_bitmap);
if (bw)
data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
if (cf1)
@@ -1056,7 +1061,7 @@
data.ch_switch.cf2 = nla_get_u32(cf2);
if (finished)
- bss->freq = data.ch_switch.freq;
+ bss->flink->freq = data.ch_switch.freq;
if (link) {
u8 link_id = nla_get_u8(link);
@@ -1110,7 +1115,8 @@
static void mlme_event_mgmt(struct i802_bss *bss,
struct nlattr *freq, struct nlattr *sig,
- const u8 *frame, size_t len)
+ const u8 *frame, size_t len,
+ int link_id)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
const struct ieee80211_mgmt *mgmt;
@@ -1148,6 +1154,8 @@
event.rx_mgmt.frame_len = len;
event.rx_mgmt.ssi_signal = ssi_signal;
event.rx_mgmt.drv_priv = bss;
+ event.rx_mgmt.link_id = link_id;
+
wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
}
@@ -1402,12 +1410,14 @@
struct nlattr *addr, struct nlattr *timed_out,
struct nlattr *freq, struct nlattr *ack,
struct nlattr *cookie, struct nlattr *sig,
- struct nlattr *wmm, struct nlattr *req_ie)
+ struct nlattr *wmm, struct nlattr *req_ie,
+ struct nlattr *link)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
u16 stype = 0, auth_type = 0;
const u8 *data;
size_t len;
+ int link_id;
if (timed_out && addr) {
mlme_timeout_event(drv, cmd, addr);
@@ -1421,6 +1431,11 @@
return;
}
+ if (link)
+ link_id = nla_get_u8(link);
+ else
+ link_id = -1;
+
data = nla_data(frame);
len = nla_len(frame);
if (len < 4 + 2 * ETH_ALEN) {
@@ -1431,10 +1446,10 @@
return;
}
wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
- ") A1=" MACSTR " A2=" MACSTR, cmd,
+ ") A1=" MACSTR " A2=" MACSTR " on link_id=%d", cmd,
nl80211_command_to_string(cmd), bss->ifname,
MAC2STR(bss->addr), MAC2STR(data + 4),
- MAC2STR(data + 4 + ETH_ALEN));
+ MAC2STR(data + 4 + ETH_ALEN), link_id);
/* PASN Authentication frame can be received with a different source MAC
* address. Allow NL80211_CMD_FRAME event with foreign addresses also.
@@ -1488,7 +1503,7 @@
break;
case NL80211_CMD_FRAME:
mlme_event_mgmt(bss, freq, sig, nla_data(frame),
- nla_len(frame));
+ nla_len(frame), link_id);
break;
case NL80211_CMD_FRAME_TX_STATUS:
mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
@@ -1568,7 +1583,7 @@
if (freq) {
wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
freq);
- drv->first_bss->freq = freq;
+ drv->first_bss->flink->freq = freq;
}
os_memset(&event, 0, sizeof(event));
@@ -1716,7 +1731,7 @@
}
}
if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
- char msg[MAX_REPORT_FREQS * 5], *pos, *end;
+ char msg[MAX_REPORT_FREQS * 5 + 1], *pos, *end;
int res;
pos = msg;
@@ -1731,11 +1746,12 @@
if (!os_snprintf_error(end - pos, res))
pos += res;
num_freqs++;
- if (num_freqs == MAX_REPORT_FREQS - 1)
+ if (num_freqs == MAX_REPORT_FREQS)
break;
}
info->freqs = freqs;
info->num_freqs = num_freqs;
+ msg[sizeof(msg) - 1] = '\0';
wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
msg);
}
@@ -3114,6 +3130,7 @@
{
union wpa_event_data event;
enum nl80211_external_auth_action act;
+ char mld_addr[50];
if (!tb[NL80211_ATTR_AKM_SUITES] ||
!tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] ||
@@ -3144,10 +3161,21 @@
event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]);
+ mld_addr[0] = '\0';
+ if (tb[NL80211_ATTR_MLD_ADDR]) {
+ event.external_auth.mld_addr =
+ nla_data(tb[NL80211_ATTR_MLD_ADDR]);
+ os_snprintf(mld_addr, sizeof(mld_addr), ", MLD ADDR: " MACSTR,
+ MAC2STR(event.external_auth.mld_addr));
+ }
+
wpa_printf(MSG_DEBUG,
- "nl80211: External auth action: %u, AKM: 0x%x",
+ "nl80211: External auth action: %u, AKM: 0x%x, SSID: %s, BSSID: " MACSTR "%s",
event.external_auth.action,
- event.external_auth.key_mgmt_suite);
+ event.external_auth.key_mgmt_suite,
+ wpa_ssid_txt(event.external_auth.ssid,
+ event.external_auth.ssid_len),
+ MAC2STR(event.external_auth.bssid), mld_addr);
wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event);
}
@@ -3267,6 +3295,7 @@
u8 *src_addr;
u16 ethertype;
enum frame_encryption encrypted;
+ int link_id;
if (!tb[NL80211_ATTR_MAC] ||
!tb[NL80211_ATTR_FRAME] ||
@@ -3278,6 +3307,11 @@
encrypted = nla_get_flag(tb[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) ?
FRAME_NOT_ENCRYPTED : FRAME_ENCRYPTED;
+ if (tb[NL80211_ATTR_MLO_LINK_ID])
+ link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
+ else
+ link_id = -1;
+
switch (ethertype) {
case ETH_P_RSN_PREAUTH:
wpa_printf(MSG_INFO, "nl80211: Got pre-auth frame from "
@@ -3288,7 +3322,7 @@
drv_event_eapol_rx2(drv->ctx, src_addr,
nla_data(tb[NL80211_ATTR_FRAME]),
nla_len(tb[NL80211_ATTR_FRAME]),
- encrypted);
+ encrypted, link_id);
break;
default:
wpa_printf(MSG_INFO,
@@ -3538,7 +3572,8 @@
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
tb[NL80211_ATTR_STA_WME],
- tb[NL80211_ATTR_REQ_IE]);
+ tb[NL80211_ATTR_REQ_IE],
+ tb[NL80211_ATTR_MLO_LINK_ID]);
break;
case NL80211_CMD_CONNECT:
case NL80211_CMD_ROAM:
@@ -3566,6 +3601,7 @@
tb[NL80211_ATTR_CHANNEL_WIDTH],
tb[NL80211_ATTR_CENTER_FREQ1],
tb[NL80211_ATTR_CENTER_FREQ2],
+ tb[NL80211_ATTR_PUNCT_BITMAP],
0);
break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
@@ -3577,6 +3613,7 @@
tb[NL80211_ATTR_CHANNEL_WIDTH],
tb[NL80211_ATTR_CENTER_FREQ1],
tb[NL80211_ATTR_CENTER_FREQ2],
+ tb[NL80211_ATTR_PUNCT_BITMAP],
1);
break;
case NL80211_CMD_DISCONNECT:
@@ -3764,7 +3801,8 @@
tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
tb[NL80211_ATTR_COOKIE],
tb[NL80211_ATTR_RX_SIGNAL_DBM],
- tb[NL80211_ATTR_STA_WME], NULL);
+ tb[NL80211_ATTR_STA_WME], NULL,
+ tb[NL80211_ATTR_MLO_LINK_ID]);
break;
case NL80211_CMD_UNEXPECTED_FRAME:
nl80211_spurious_frame(bss, tb, 0);
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index c14a91b..9a0ac03 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -424,7 +424,8 @@
* interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all stations, on the interface identified
- * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ * by %NL80211_ATTR_IFINDEX. For MLD station, MLD address is used in
+ * %NL80211_ATTR_MAC. %NL80211_ATTR_MGMT_SUBTYPE and
* %NL80211_ATTR_REASON_CODE can optionally be used to specify which type
* of disconnection indication should be sent to the station
* (Deauthentication or Disassociation frame and reason code for that
@@ -1166,6 +1167,23 @@
* %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH
* command interface.
*
+ * Host driver sends MLD address of the AP with %NL80211_ATTR_MLD_ADDR in
+ * %NL80211_CMD_EXTERNAL_AUTH event to indicate user space to enable MLO
+ * during the authentication offload in STA mode while connecting to MLD
+ * APs. Host driver should check %NL80211_ATTR_MLO_SUPPORT flag capability
+ * in %NL80211_CMD_CONNECT to know whether the user space supports enabling
+ * MLO during the authentication offload or not.
+ * User space should enable MLO during the authentication only when it
+ * receives the AP MLD address in authentication offload request. User
+ * space shouldn't enable MLO when the authentication offload request
+ * doesn't indicate the AP MLD address even if the AP is MLO capable.
+ * User space should use %NL80211_ATTR_MLD_ADDR as peer's MLD address and
+ * interface address identified by %NL80211_ATTR_IFINDEX as self MLD
+ * address. User space and host driver to use MLD addresses in RA, TA and
+ * BSSID fields of the frames between them, and host driver translates the
+ * MLD addresses to/from link addresses based on the link chosen for the
+ * authentication.
+ *
* Host driver reports this status on an authentication failure to the
* user space through the connect result as the user space would have
* initiated the connection through the connect request.
@@ -1281,6 +1299,16 @@
* @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_SET_HW_TIMESTAMP: Enable/disable HW timestamping of Timing
+ * measurement and Fine timing measurement frames. If %NL80211_ATTR_MAC
+ * is included, enable/disable HW timestamping only for frames to/from the
+ * specified MAC address. Otherwise enable/disable HW timestamping for
+ * all TM/FTM frames (including ones that were enabled with specific MAC
+ * address). If %NL80211_ATTR_HW_TIMESTAMP_ENABLED is not included, disable
+ * HW timestamping.
+ * The number of peers that HW timestamping can be enabled for concurrently
+ * is indicated by %NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1532,6 +1560,8 @@
NL80211_CMD_MODIFY_LINK_STA,
NL80211_CMD_REMOVE_LINK_STA,
+ NL80211_CMD_SET_HW_TIMESTAMP,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2751,6 +2781,19 @@
* the incoming frame RX timestamp.
* @NL80211_ATTR_TD_BITMAP: Transition Disable bitmap, for subsequent
* (re)associations.
+ *
+ * @NL80211_ATTR_PUNCT_BITMAP: (u32) Preamble puncturing bitmap, lowest
+ * bit corresponds to the lowest 20 MHz channel. Each bit set to 1
+ * indicates that the sub-channel is punctured. Higher 16 bits are
+ * reserved.
+ *
+ * @NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS: Maximum number of peers that HW
+ * timestamping can be enabled for concurrently (u16), a wiphy attribute.
+ * A value of 0xffff indicates setting for all peers (i.e. not specifying
+ * an address with %NL80211_CMD_SET_HW_TIMESTAMP) is supported.
+ * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should
+ * be enabled or not (flag attribute).
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3280,6 +3323,11 @@
NL80211_ATTR_RX_HW_TIMESTAMP,
NL80211_ATTR_TD_BITMAP,
+ NL80211_ATTR_PUNCT_BITMAP,
+
+ NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
+ NL80211_ATTR_HW_TIMESTAMP_ENABLED,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -5869,6 +5917,7 @@
#define NL80211_KEK_LEN 16
#define NL80211_KCK_EXT_LEN 24
#define NL80211_KEK_EXT_LEN 32
+#define NL80211_KCK_EXT_LEN_32 32
#define NL80211_REPLAY_CTR_LEN 8
/**
@@ -6294,6 +6343,15 @@
* might apply, e.g. no scans in progress, no offchannel operations
* in progress, and no active connections.
*
+ * @NL80211_EXT_FEATURE_PUNCT: Driver supports preamble puncturing in AP mode.
+ *
+ * @NL80211_EXT_FEATURE_SECURE_NAN: Device supports NAN Pairing which enables
+ * authentication, data encryption and message integrity.
+ *
+ * @NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA: Device supports randomized TA
+ * in authentication and deauthentication frames sent to unassociated peer
+ * using @NL80211_CMD_FRAME.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -6362,6 +6420,9 @@
NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
NL80211_EXT_FEATURE_RADAR_BACKGROUND,
NL80211_EXT_FEATURE_POWERED_ADDR_CHANGE,
+ NL80211_EXT_FEATURE_PUNCT,
+ NL80211_EXT_FEATURE_SECURE_NAN,
+ NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6476,8 +6537,14 @@
* @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with
* %NL80211_ATTR_SCAN_FREQ_KHZ. This also means
* %NL80211_ATTR_SCAN_FREQUENCIES will not be included.
- * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by
- * 2.4/5 GHz APs
+ * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for collocated APs reported by
+ * 2.4/5 GHz APs. When the flag is set, the scan logic will use the
+ * information from the RNR element found in beacons/probe responses
+ * received on the 2.4/5 GHz channels to actively scan only the 6GHz
+ * channels on which APs are expected to be found. Note that when not set,
+ * the scan logic would scan all 6GHz channels, but since transmission of
+ * probe requests on non PSC channels is limited, it is highly likely that
+ * these channels would passively be scanned.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index b893522..b21f12d 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -445,7 +445,8 @@
sizeof(data->mschapv2_auth_response));
} else {
pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR,
- RADIUS_VENDOR_ID_MICROSOFT, 1, 6);
+ RADIUS_VENDOR_ID_MICROSOFT, 1, 7);
+ *pos++ = data->mschapv2_ident;
os_memcpy(pos, "Failed", 6);
pos += 6;
AVP_PAD(req, pos);
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index e1f72ac..5d50726 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4113,9 +4113,11 @@
/*
* Better remain on operating channel instead of listen channel
* when running a group.
+ * Wait 120 ms to let the P2P GO to send its beacon on the
+ * intended TBTT.
*/
p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel");
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, 120000);
return;
}
p2p_listen_in_find(p2p, 0);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index afd8969..55db8a5 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "p2p_i.h"
@@ -697,6 +698,7 @@
unsigned int i;
u8 op_class, op_channel;
char txt[100], *pos, *end;
+ bool is_6ghz_capab;
int res;
/*
@@ -718,6 +720,8 @@
if (!size)
return;
/* Filter out frequencies that are not acceptable for P2P use */
+ is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
+ p2p_is_peer_6ghz_capab(p2p, dev->info.p2p_device_addr);
i = 0;
while (i < size) {
if (p2p_freq_to_channel(p2p->pref_freq_list[i].freq,
@@ -725,7 +729,9 @@
(!p2p_channels_includes(&p2p->cfg->channels,
op_class, op_channel) &&
(go || !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel)))) {
+ op_class, op_channel))) ||
+ (is_6ghz_freq(p2p->pref_freq_list[i].freq) &&
+ !is_6ghz_capab)) {
p2p_dbg(p2p,
"Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
p2p->pref_freq_list[i].freq, go);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index bca5b90..941ec00 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -598,9 +598,14 @@
p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
p2p->invite_peer = dev;
dev->invitation_reqs++;
+
+ /* In case of an active P2P GO use a shorter wait time to avoid
+ * issues if not sending out multiple consecutive Beacon frames. */
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 500) < 0) {
+ wpabuf_head(req), wpabuf_len(req),
+ p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO ?
+ 150 : 500) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
/* Use P2P find to recover and retry */
p2p_set_timeout(p2p, 0, 0);
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 2bf3e8e..d06ad86 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -84,6 +84,7 @@
/* not defined IEEE Std 802.1X-2010 */
struct ieee802_1x_kay *kay;
+ u8 offload;
};
static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
@@ -188,6 +189,7 @@
sm->protect_frames = false;
sm->replay_protect = false;
sm->validate_frames = Checked;
+ sm->offload = sm->kay->macsec_offload;
sm->port_valid = false;
sm->controlled_port_enabled = true;
@@ -197,6 +199,7 @@
secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
+ secy_cp_control_offload(sm->kay, sm->offload);
}
@@ -208,6 +211,7 @@
sm->protect_frames = sm->kay->macsec_protect;
sm->replay_protect = sm->kay->macsec_replay_protect;
+ sm->offload = sm->kay->macsec_offload;
sm->validate_frames = sm->kay->macsec_validate;
sm->current_cipher_suite = sm->cipher_suite;
@@ -223,6 +227,7 @@
secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
+ secy_cp_control_offload(sm->kay, sm->offload);
}
@@ -462,6 +467,7 @@
sm->validate_frames = kay->macsec_validate;
sm->replay_protect = kay->macsec_replay_protect;
sm->replay_window = kay->macsec_replay_window;
+ sm->offload = kay->macsec_offload;
sm->controlled_port_enabled = false;
@@ -491,6 +497,7 @@
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
+ secy_cp_control_offload(sm->kay, sm->offload);
SM_STEP_RUN(CP);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 3c55c5a..66c65aa 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -3477,8 +3477,8 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
- u16 port, u8 priority, u32 macsec_csindex,
- const char *ifname, const u8 *addr)
+ u8 macsec_offload, u16 port, u8 priority,
+ u32 macsec_csindex, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3537,6 +3537,7 @@
kay->macsec_validate = Disabled;
kay->macsec_replay_protect = false;
kay->macsec_replay_window = 0;
+ kay->macsec_offload = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
kay->mka_hello_time = MKA_HELLO_TIME;
} else {
@@ -3553,6 +3554,7 @@
kay->macsec_validate = Strict;
kay->macsec_replay_protect = macsec_replay_protect;
kay->macsec_replay_window = macsec_replay_window;
+ kay->macsec_offload = macsec_offload;
kay->mka_hello_time = MKA_HELLO_TIME;
}
@@ -3757,6 +3759,7 @@
secy_cp_control_protect_frames(kay, kay->macsec_protect);
secy_cp_control_replay(kay, kay->macsec_replay_protect,
kay->macsec_replay_window);
+ secy_cp_control_offload(kay, kay->macsec_offload);
if (secy_create_transmit_sc(kay, participant->txsc))
goto fail;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 525679f..545a99b 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -166,6 +166,7 @@
int (*delete_transmit_sa)(void *ctx, struct transmit_sa *sa);
int (*enable_transmit_sa)(void *ctx, struct transmit_sa *sa);
int (*disable_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*set_offload)(void *ctx, u8 offload);
};
struct ieee802_1x_kay {
@@ -206,6 +207,7 @@
bool is_key_server;
bool is_obliged_key_server;
char if_name[IFNAMSIZ];
+ u8 macsec_offload;
unsigned int macsec_csindex; /* MACsec cipher suite table index */
int mka_algindex; /* MKA alg table index */
@@ -240,8 +242,8 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
- u16 port, u8 priority, u32 macsec_csindex,
- const char *ifname, const u8 *addr);
+ u8 macsec_offload, u16 port, u8 priority,
+ u32 macsec_csindex, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c
index 0f36e6b..f35baad 100644
--- a/src/pae/ieee802_1x_secy_ops.c
+++ b/src/pae/ieee802_1x_secy_ops.c
@@ -85,6 +85,26 @@
}
+int secy_cp_control_offload(struct ieee802_1x_kay *kay, u8 offload)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->set_offload) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy set_offload operation not supported");
+ return -1;
+ }
+
+ return ops->set_offload(ops->ctx, offload);
+}
+
+
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs)
{
struct ieee802_1x_kay_ctx *ops;
diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h
index 18c06f6..b82507b 100644
--- a/src/pae/ieee802_1x_secy_ops.h
+++ b/src/pae/ieee802_1x_secy_ops.h
@@ -23,6 +23,7 @@
int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, bool flag);
int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, bool enabled);
int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool flag, u32 win);
+int secy_cp_control_offload(struct ieee802_1x_kay *kay, u8 offload);
int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs);
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
enum confidentiality_offset co);
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e3c7892..cd3ef3e 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -92,7 +92,7 @@
const u8 *pkt, size_t pkt_len);
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
void (*transition_disable)(void *ctx, u8 bitmap);
- void (*store_ptk)(void *ctx, u8 *addr, int cipher,
+ void (*store_ptk)(void *ctx, const 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,
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 4d52542..56a30c8 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -511,7 +511,7 @@
}
sm->tk_set = true;
- wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ wpa_sm_store_ptk(sm, bssid, sm->pairwise_cipher,
sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
return 0;
}
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index ed43cc1..a3c13b1 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -477,7 +477,7 @@
}
static inline void wpa_sm_store_ptk(struct wpa_sm *sm,
- u8 *addr, int cipher,
+ const u8 *addr, int cipher,
u32 life_time, struct wpa_ptk *ptk)
{
if (sm->ctx->store_ptk)
diff --git a/src/utils/browser.c b/src/utils/browser.c
index c0f4380..b5d5ba7 100644
--- a/src/utils/browser.c
+++ b/src/utils/browser.c
@@ -370,11 +370,21 @@
#ifdef USE_WEBKIT2
if (ignore_tls) {
+#if WEBKIT_CHECK_VERSION(2, 32, 0)
+ WebKitWebContext *wkctx;
+ WebKitWebsiteDataManager *wkmgr;
+
+ wkctx = webkit_web_context_get_default();
+ wkmgr = webkit_web_context_get_website_data_manager(wkctx);
+ webkit_website_data_manager_set_tls_errors_policy(
+ wkmgr, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+#else
WebKitWebContext *wkctx;
wkctx = webkit_web_context_get_default();
webkit_web_context_set_tls_errors_policy(
wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE);
+#endif
}
#endif /* USE_WEBKIT2 */