[wpa_supplicant] Cumulative patch from fe468b071
Bug: 124017368
Test: Device boots up and connects to WPA3/OWE wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: DPP functional test.
Test: Regression test passed (Bug: 124301325)
fe468b071 HE: Fix set_he_cap() parsing of config options for MU EDCA Params
f3a841bbf Do not disassociate not-associated STA on timeout
91205c8eb OpenSSL: Fix uninitialized variable in CRL reloading corner case
092a19222 Use for_each_element() in ieee802_11_parse_elems()
b50a63896 common: Use for_each_element_id/_extid for get_ie/get_ie_ext/get_vendor_ie
b64479742 common: Use for_each_element_id() in mb_ies_info_by_ies()
9008048f0 common: Use for_each_element_id() in ieee802_11_vendor_ie_concat()
eb84238df common: Use for_each_element() in ieee802_11_ie_count()
0e0c31bdc common: Add strongly typed element iteration macros
525923b1d tests: EAPOL-Key fuzzing tool
02a0a2393 RSN: Do not start preauthentication timer without candidates
1e5506588 JSON: Fix string parsing when \\ escape is at the end of buffer
0dedcb315 JSON: Fix parsing of a number from the end of the buffer
79fa1b453 tests: JSON parser fuzzer
62269c8d8 TLS: Fix X.509 certificate name conversion into empty string
3eae9766b TLS: Fix ASN.1 parsing with no room for the header
fbc2123a1 TLS: Fix AlertDescription for missing partial processing case
1ac9c020b tests: TLS fuzzing tool
f3cca8b1e TLS server: Check credentials have been configured before using them
19dd7a736 TLS server: Local failure information on verify_data mismatch
f08ab18bf TLS server: Add internal callbacks get_failed, get_*_alerts
b642ab406 TLS server: More complete logging of ClientHello decode errors
fdd8a2f0b TLS client: Fix peer certificate event checking for probing
e5bffe1aa OpenSSL: Add more handshake message names to debug
21cd8f831 nl80211: Use wpa_ssid_txt() for debug messages more consistently
bbdb50146 Note HT overrides in debug log only if set
f2a6ac63e P2P: Update find_start timer only when p2p_scan is started.
c4e90da6d MBO: Move the WNM-Notification subtype definitions to common location
105b14f54 HS 2.0: Update the T&C Acceptance subtype value
65b487ae5 HS 2.0: Add QUIET=1 support for building hs20-osu-client
73f285dad Add FT-PSK to GET_CAPABILITY key_mgmt
6110753b1 nl80211: Clear PMKID add command message buffer
0fa33e05b nl80211: Clear connect command message buffer
b14e8ea1d nl80211: Request kernel to trim off payload of netlink requests from acks
789b48bb4 EAP peer: Clear temporary message buffers before freeing
8f99a3c26 Clear config item writing buffer before freeing it
a68e9b698 D-Bus: Fix P2P DeleteService dict iteration
0607346f1 D-Bus: Fix a memory leak in DeleteService handler
d05dda61d PEAP: Explicitly clear temporary keys from memory when using CMK
4e1cd3468 EAP-PEAP: Derive EMSK and use 128-octet derivation for MSK
d8c20ec59 DPP: Clear dpp_listen_freq on remain-on-channel failure
59fa20538 P2P: Allow the avoid channels for P2P discovery/negotiation
e34cd9f06 WNM: Fix WNM-Sleep Mode Request bounds checking
159a7fbde crl_reload_interval: Add CRL reloading support
83c860813 AP: Add wpa_psk_file reloading in runtime
ec5c39a55 AP: Allow identifying which passphrase station used with wpa_psk_file
b08c9ad0c AP: Expose PMK outside of wpa_auth module
89896c000 tests: Use python3 compatible print statement
bab493b90 tests: Use python3 compatible "except" statement
0dab47733 Write multi_ap_backhaul_sta to wpa_supplicant config
98251c6f2 dbus: Document more possible BSS/RSA/KeyMgmt values
1e591df06 Check supported types in wpas_mac_addr_rand_scan_set()
c85249aa1 Fix test compilation error related to sme_event_unprot_disconnect()
42d308635 SAE: Advertise Password Identifier use
59c693064 HS 2.0 server: Command line option to fetch the version information
2d1762fa4 HS 2.0 server: Alternative subrem updateNode for certificate credentials
d97cf2a11 HS 2.0 server: Use noMOUpdate in client certificate subrem
13a200a92 FILS: Remove notes about experimental implementation
86d4e0537 dbus: Expose support of SAE key management in BSS properties
Change-Id: Id507b73f1f4a2e356cbcd3bfcfb9dcd23c8fd9e0
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 771e766..e0e6fe5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -40,6 +40,9 @@
#include "driver_nl80211.h"
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif /* NETLINK_CAP_ACK */
/* support for extack if compilation headers are too old */
#ifndef NETLINK_EXT_ACK
#define NETLINK_EXT_ACK 11
@@ -406,6 +409,11 @@
setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
NETLINK_EXT_ACK, &opt, sizeof(opt));
+ /* try to set NETLINK_CAP_ACK to 1, ignoring errors */
+ opt = 1;
+ setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_CAP_ACK, &opt, sizeof(opt));
+
err = nl_send_auto_complete(nl_handle, msg);
if (err < 0)
goto out;
@@ -1469,7 +1477,7 @@
{
struct nl_msg *msg;
- sig->current_signal = -9999;
+ sig->current_signal = -WPA_INVALID_NOISE;
sig->current_txrate = 0;
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
@@ -1531,7 +1539,7 @@
{
struct nl_msg *msg;
- sig_change->current_noise = 9999;
+ sig_change->current_noise = WPA_INVALID_NOISE;
sig_change->frequency = drv->assoc_freq;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
@@ -1539,6 +1547,70 @@
}
+static int get_channel_info(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_channel_info *chan_info = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
+ chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ chan_info->frequency =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ chan_info->chanwidth = convert2width(
+ nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ enum nl80211_channel_type ct =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+ switch (ct) {
+ case NL80211_CHAN_HT40MINUS:
+ chan_info->sec_channel = -1;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_info->sec_channel = 1;
+ break;
+ default:
+ chan_info->sec_channel = 0;
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ chan_info->center_frq1 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ chan_info->center_frq2 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ if (chan_info->center_frq2) {
+ u8 seg1_idx = 0;
+
+ if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
+ NUM_HOSTAPD_MODES)
+ chan_info->seg1_idx = seg1_idx;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ return send_and_recv_msgs(drv, msg, get_channel_info, ci);
+}
+
+
static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
void *handle)
{
@@ -2169,6 +2241,11 @@
ret = -1;
#endif /* CONFIG_DPP */
#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_OCV
+ /* SA Query Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_OCV */
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
ret = -1;
@@ -2962,7 +3039,7 @@
#endif /* CONFIG_DRIVER_NL80211_QCA */
if (alg == WPA_ALG_PMK &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return nl80211_set_pmk(drv, key, key_len, addr);
if (alg == WPA_ALG_NONE) {
@@ -3165,7 +3242,8 @@
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
- int local_state_change)
+ int local_state_change,
+ struct nl_handle *nl_connect)
{
int ret;
struct nl_msg *msg;
@@ -3179,7 +3257,10 @@
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (nl_connect)
+ ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ else
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3190,7 +3271,8 @@
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- int reason_code)
+ int reason_code,
+ struct nl_handle *nl_connect)
{
int ret;
int drv_associated = drv->associated;
@@ -3199,7 +3281,7 @@
nl80211_mark_disconnected(drv);
/* Disconnect command doesn't need BSSID - it uses cached value */
ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
- reason_code, 0);
+ reason_code, 0, nl_connect);
/*
* For locally generated disconnect, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
@@ -3221,13 +3303,19 @@
nl80211_mark_disconnected(drv);
return nl80211_leave_ibss(drv, 1);
}
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, reason_code);
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ struct nl_handle *nl_connect = NULL;
+
+ if (bss->use_nl_connect)
+ nl_connect = bss->nl_connect;
+ return wpa_driver_nl80211_disconnect(drv, reason_code,
+ nl_connect);
+ }
wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
__func__, MAC2STR(addr), reason_code);
nl80211_mark_disconnected(drv);
ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
- reason_code, 0);
+ reason_code, 0, NULL);
/*
* For locally generated deauthenticate, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
@@ -3389,8 +3477,8 @@
goto fail;
}
if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid))
goto fail;
@@ -3957,7 +4045,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
u8 cmd = NL80211_CMD_NEW_BEACON;
- int ret;
+ int ret = -ENOBUFS;
int beacon_set;
int num_suites;
int smps_mode;
@@ -3986,8 +4074,8 @@
wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
- wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
params->head) ||
@@ -4163,6 +4251,29 @@
goto fail;
}
+ if (params->ftm_responder) {
+ struct nlattr *ftm;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
+ if (!ftm ||
+ nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
+ (params->lci &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
+ wpabuf_len(params->lci),
+ wpabuf_head(params->lci))) ||
+ (params->civic &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
+ wpabuf_len(params->civic),
+ wpabuf_head(params->civic))))
+ goto fail;
+ nla_nest_end(msg, ftm);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -4214,7 +4325,7 @@
return ret;
fail:
nlmsg_free(msg);
- return -ENOBUFS;
+ return ret;
}
@@ -5178,8 +5289,8 @@
params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
goto fail;
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
@@ -5340,8 +5451,8 @@
}
if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid))
return -1;
@@ -5465,9 +5576,16 @@
return -1;
}
+ if (params->req_key_mgmt_offload &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
+ wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
+ if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
+ return -1;
+ }
+
/* Add PSK in case of 4-way handshake offload */
if (params->psk &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) {
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
return -1;
@@ -5598,9 +5716,10 @@
goto fail;
if (nl_connect)
- ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_connect, msg,
+ NULL, (void *) -1);
else
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
msg = NULL;
if (ret) {
@@ -5612,6 +5731,7 @@
}
fail:
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return ret;
@@ -5642,7 +5762,7 @@
"disconnecting before reassociation "
"attempt");
if (wpa_driver_nl80211_disconnect(
- drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+ drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
return -1;
ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
}
@@ -5673,8 +5793,13 @@
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- if (params->auth_alg & WPA_AUTH_ALG_SAE)
+ if (params->auth_alg & WPA_AUTH_ALG_SAE) {
nl_connect = bss->nl_connect;
+ bss->use_nl_connect = 1;
+ } else {
+ bss->use_nl_connect = 0;
+ }
+
return wpa_driver_nl80211_connect(drv, params, nl_connect);
}
@@ -6281,6 +6406,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *txq, *params;
+ int res;
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
if (!msg)
@@ -6326,7 +6452,11 @@
nla_nest_end(msg, txq);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
+ queue, aifs, cw_min, cw_max, burst_time, res);
+ if (res == 0)
return 0;
msg = NULL;
fail:
@@ -6625,9 +6755,12 @@
}
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
- if (bridge_ifname)
- linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
- name);
+ if (bridge_ifname &&
+ linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+ name) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to remove interface %s from bridge %s: %s",
+ name, bridge_ifname, strerror(errno));
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
nl80211_remove_iface(drv, if_nametoindex(name));
@@ -7796,11 +7929,12 @@
params->fils_cache_id)) ||
(params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
}
@@ -8572,6 +8706,8 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int res;
char *pos, *end;
+ struct nl_msg *msg;
+ char alpha2[3] = { 0, 0, 0 };
pos = buf;
end = buf + buflen;
@@ -8716,6 +8852,23 @@
pos += res;
}
+ msg = nlmsg_alloc();
+ if (msg &&
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
+ if (send_and_recv_msgs(drv, msg, nl80211_get_country,
+ alpha2) == 0 &&
+ alpha2[0]) {
+ res = os_snprintf(pos, end - pos, "country=%s\n",
+ alpha2);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+ } else {
+ nlmsg_free(msg);
+ }
+
return pos - buf;
}
@@ -9282,8 +9435,8 @@
size_t mesh_id_len)
{
if (mesh_id) {
- wpa_hexdump_ascii(MSG_DEBUG, " * Mesh ID (SSID)",
- mesh_id, mesh_id_len);
+ wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
+ wpa_ssid_txt(mesh_id, mesh_id_len));
return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
}
@@ -10648,6 +10801,49 @@
}
+static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
+ int val)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
+ val ? "Enable" : "Disable", bridge_ifname);
+
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
+ goto fail;
+
+ if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
+ if (linux_br_del_if(drv->global->ioctl_sock,
+ bridge_ifname, bss->ifname)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to remove interface %s from bridge %s",
+ bss->ifname, bridge_ifname);
+ return -1;
+ }
+ bss->added_if_into_bridge = 0;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (!ret) {
+ if (bridge_ifname[0] && val &&
+ i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
+ return -1;
+ return 0;
+ }
+
+fail:
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
+
+ return ret;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -10707,6 +10903,7 @@
.resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
+ .channel_info = nl80211_channel_info,
.send_frame = nl80211_send_frame,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
@@ -10776,4 +10973,5 @@
.get_ext_capab = nl80211_get_ext_capab,
.update_connect_params = nl80211_update_connection_params,
.send_external_auth_status = nl80211_send_external_auth_status,
+ .set_4addr_mode = nl80211_set_4addr_mode,
};