summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-05-27 06:17:35 +0300
committerDavid S. Miller <davem@davemloft.net>2020-05-27 06:17:35 +0300
commit745bd6f44cd3413f429ed3e2c7744c8abf8630d5 (patch)
tree29ccc5ac8cb3faca99f132e85fcb0b382e7cdcb1 /drivers/net
parent0e3481195b155da4b9b94ad4d64bbf531ce62d16 (diff)
parent60689de46c7f6a0028c8b37b6f03db68cbfad8ed (diff)
downloadlinux-745bd6f44cd3413f429ed3e2c7744c8abf8630d5.tar.xz
Merge tag 'mac80211-next-for-net-next-2020-04-25' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== One batch of changes, containing: * hwsim improvements from Jouni and myself, to be able to test more scenarios easily * some more HE (802.11ax) support * some initial S1G (sub 1 GHz) work for fractional MHz channels * some (action) frame registration updates to help DPP support * along with other various improvements/fixes ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c26
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c6
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c63
-rw-r--r--drivers/net/wireless/mac80211_hwsim.h8
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c16
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/cfg80211.c83
8 files changed, 143 insertions, 81 deletions
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 5ffe55801ca4..d9117ebf2809 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1178,8 +1178,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
sizeof(arg->peer_he_cap_macinfo));
memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
sizeof(arg->peer_he_cap_phyinfo));
- memcpy(&arg->peer_he_ops, &vif->bss_conf.he_operation,
- sizeof(arg->peer_he_ops));
+ arg->peer_he_ops = vif->bss_conf.he_oper.params;
/* the top most byte is used to indicate BSS color info */
arg->peer_he_ops &= 0xffffff;
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 37cf602d8adf..67f8f2aa7a53 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -3249,22 +3249,19 @@ static int ath6kl_get_antenna(struct wiphy *wiphy,
return 0;
}
-static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- u16 frame_type, bool reg)
+static void ath6kl_update_mgmt_frame_registrations(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct mgmt_frame_regs *upd)
{
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
- __func__, frame_type, reg);
- if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
- /*
- * Note: This notification callback is not allowed to sleep, so
- * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
- * hardcode target to report Probe Request frames all the time.
- */
- vif->probe_req_report = reg;
- }
+ /*
+ * FIXME: send WMI_PROBE_REQ_REPORT_CMD here instead of hardcoding
+ * the reporting in the target all the time, this callback
+ * *is* allowed to sleep after all.
+ */
+ vif->probe_req_report =
+ upd->interface_stypes & BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
}
static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
@@ -3464,7 +3461,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
.remain_on_channel = ath6kl_remain_on_channel,
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
.mgmt_tx = ath6kl_mgmt_tx,
- .mgmt_frame_register = ath6kl_mgmt_frame_register,
+ .update_mgmt_frame_registrations =
+ ath6kl_update_mgmt_frame_registrations,
.get_antenna = ath6kl_get_antenna,
.sched_scan_start = ath6kl_cfg80211_sscan_start,
.sched_scan_stop = ath6kl_cfg80211_sscan_stop,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index fbec6dd551d6..a757abd7a599 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5031,21 +5031,15 @@ brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
}
static void
-brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- u16 frame_type, bool reg)
+brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct mgmt_frame_regs *upd)
{
struct brcmf_cfg80211_vif *vif;
- u16 mgmt_type;
- brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
-
- mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
- if (reg)
- vif->mgmt_rx_reg |= BIT(mgmt_type);
- else
- vif->mgmt_rx_reg &= ~BIT(mgmt_type);
+
+ vif->mgmt_rx_reg = upd->interface_stypes;
}
@@ -5460,7 +5454,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.change_station = brcmf_cfg80211_change_station,
.sched_scan_start = brcmf_cfg80211_sched_scan_start,
.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
- .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+ .update_mgmt_frame_registrations =
+ brcmf_cfg80211_update_mgmt_frame_registrations,
.mgmt_tx = brcmf_cfg80211_mgmt_tx,
.remain_on_channel = brcmf_p2p_remain_on_channel,
.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 246265904b98..a7264b282d79 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
*
- * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014, 2018 - 2020 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
*
* Contact Information:
* Intel Linux Wireless <linuxwifi@intel.com>
@@ -1430,7 +1429,8 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
*/
if (ieee80211_get_vht_max_nss(&vht_cap,
IEEE80211_VHT_CHANWIDTH_160MHZ,
- 0, true) < sta->rx_nss)
+ 0, true,
+ sta->rx_nss) < sta->rx_nss)
return RATE_MCS_CHAN_WIDTH_80;
return RATE_MCS_CHAN_WIDTH_160;
case IEEE80211_STA_RX_BW_80:
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 0528d4cb4d37..f4ded2f2ee3b 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1068,6 +1068,47 @@ static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
return res;
}
+static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw,
+ const u8 *addr, bool add)
+{
+ struct mac80211_hwsim_data *data = hw->priv;
+ u32 _portid = READ_ONCE(data->wmediumd);
+ struct sk_buff *skb;
+ void *msg_head;
+
+ if (!_portid && !hwsim_virtio_enabled)
+ return;
+
+ skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
+ add ? HWSIM_CMD_ADD_MAC_ADDR :
+ HWSIM_CMD_DEL_MAC_ADDR);
+ if (!msg_head) {
+ pr_debug("mac80211_hwsim: problem with msg_head\n");
+ goto nla_put_failure;
+ }
+
+ if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
+ ETH_ALEN, data->addresses[1].addr))
+ goto nla_put_failure;
+
+ if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr))
+ goto nla_put_failure;
+
+ genlmsg_end(skb, msg_head);
+
+ if (hwsim_virtio_enabled)
+ hwsim_tx_virtio(data, skb);
+ else
+ hwsim_unicast_netgroup(data, skb, _portid);
+ return;
+nla_put_failure:
+ nlmsg_free(skb);
+}
+
static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate)
{
u16 result = 0;
@@ -1545,6 +1586,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
vif->addr);
hwsim_set_magic(vif);
+ if (vif->type != NL80211_IFTYPE_MONITOR)
+ mac80211_hwsim_config_mac_nl(hw, vif->addr, true);
+
vif->cab_queue = 0;
vif->hw_queue[IEEE80211_AC_VO] = 0;
vif->hw_queue[IEEE80211_AC_VI] = 1;
@@ -1584,6 +1628,8 @@ static void mac80211_hwsim_remove_interface(
vif->addr);
hwsim_check_magic(vif);
hwsim_clear_magic(vif);
+ if (vif->type != NL80211_IFTYPE_MONITOR)
+ mac80211_hwsim_config_mac_nl(hw, vif->addr, false);
}
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1781,6 +1827,8 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
data->rx_filter = 0;
if (*total_flags & FIF_ALLMULTI)
data->rx_filter |= FIF_ALLMULTI;
+ if (*total_flags & FIF_MCAST_ACTION)
+ data->rx_filter |= FIF_MCAST_ACTION;
*total_flags = data->rx_filter;
}
@@ -2104,6 +2152,8 @@ static void hw_scan_work(struct work_struct *work)
hwsim->hw_scan_vif = NULL;
hwsim->tmp_chan = NULL;
mutex_unlock(&hwsim->mutex);
+ mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr,
+ false);
return;
}
@@ -2177,6 +2227,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
mutex_unlock(&hwsim->mutex);
+ mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true);
wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n");
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0);
@@ -2220,6 +2271,7 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw,
pr_debug("hwsim sw_scan request, prepping stuff\n");
memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN);
+ mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true);
hwsim->scanning = true;
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
@@ -2236,6 +2288,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
pr_debug("hwsim sw_scan_complete\n");
hwsim->scanning = false;
+ mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false);
eth_zero_addr(hwsim->scan_addr);
mutex_unlock(&hwsim->mutex);
@@ -2413,6 +2466,11 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
}
+static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ return 1;
+}
+
#define HWSIM_COMMON_OPS \
.tx = mac80211_hwsim_tx, \
.start = mac80211_hwsim_start, \
@@ -2423,6 +2481,7 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
.config = mac80211_hwsim_config, \
.configure_filter = mac80211_hwsim_configure_filter, \
.bss_info_changed = mac80211_hwsim_bss_info_changed, \
+ .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \
.sta_add = mac80211_hwsim_sta_add, \
.sta_remove = mac80211_hwsim_sta_remove, \
.sta_notify = mac80211_hwsim_sta_notify, \
@@ -3003,6 +3062,10 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
hw->wiphy->interface_modes = param->iftypes;
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h
index 28ade92adcb4..9dceed77c5d6 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -75,6 +75,12 @@ enum hwsim_tx_control_flags {
* @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
* @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
* %HWSIM_ATTR_RADIO_ID
+ * @HWSIM_CMD_ADD_MAC_ADDR: add a receive MAC address (given in the
+ * %HWSIM_ATTR_ADDR_RECEIVER attribute) to a device identified by
+ * %HWSIM_ATTR_ADDR_TRANSMITTER. This lets wmediumd forward frames
+ * to this receiver address for a given station.
+ * @HWSIM_CMD_DEL_MAC_ADDR: remove the MAC address again, the attributes
+ * are the same as to @HWSIM_CMD_ADD_MAC_ADDR.
* @__HWSIM_CMD_MAX: enum limit
*/
enum {
@@ -85,6 +91,8 @@ enum {
HWSIM_CMD_NEW_RADIO,
HWSIM_CMD_DEL_RADIO,
HWSIM_CMD_GET_RADIO,
+ HWSIM_CMD_ADD_MAC_ADDR,
+ HWSIM_CMD_DEL_MAC_ADDR,
__HWSIM_CMD_MAX,
};
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 12bfd653a405..97813ac291ae 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -269,17 +269,12 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
* CFG802.11 operation handler to register a mgmt frame.
*/
static void
-mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- u16 frame_type, bool reg)
+mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct mgmt_frame_regs *upd)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
- u32 mask;
-
- if (reg)
- mask = priv->mgmt_frame_mask | BIT(frame_type >> 4);
- else
- mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4);
+ u32 mask = upd->interface_stypes;
if (mask != priv->mgmt_frame_mask) {
priv->mgmt_frame_mask = mask;
@@ -4187,7 +4182,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.del_key = mwifiex_cfg80211_del_key,
.set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key,
.mgmt_tx = mwifiex_cfg80211_mgmt_tx,
- .mgmt_frame_register = mwifiex_cfg80211_mgmt_frame_register,
+ .update_mgmt_frame_registrations =
+ mwifiex_cfg80211_update_mgmt_frame_registrations,
.remain_on_channel = mwifiex_cfg80211_remain_on_channel,
.cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel,
.set_default_key = mwifiex_cfg80211_set_default_key,
diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
index 8be17106008d..54cdf3ad09d7 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
@@ -389,55 +389,57 @@ static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed)
}
static void
-qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
- u16 frame_type, bool reg)
+qtnf_update_mgmt_frame_registrations(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ struct mgmt_frame_regs *upd)
{
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
- u16 mgmt_type;
- u16 new_mask;
- u16 qlink_frame_type = 0;
+ u16 new_mask = upd->interface_stypes;
+ u16 old_mask = vif->mgmt_frames_bitmask;
+ static const struct {
+ u16 mask, qlink_type;
+ } updates[] = {
+ {
+ .mask = BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_ASSOC_REQ >> 4),
+ .qlink_type = QLINK_MGMT_FRAME_ASSOC_REQ,
+ },
+ {
+ .mask = BIT(IEEE80211_STYPE_AUTH >> 4),
+ .qlink_type = QLINK_MGMT_FRAME_AUTH,
+ },
+ {
+ .mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+ .qlink_type = QLINK_MGMT_FRAME_PROBE_REQ,
+ },
+ {
+ .mask = BIT(IEEE80211_STYPE_ACTION >> 4),
+ .qlink_type = QLINK_MGMT_FRAME_ACTION,
+ },
+ };
+ unsigned int i;
- mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+ if (new_mask == old_mask)
+ return;
- if (reg)
- new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type);
- else
- new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type);
+ for (i = 0; i < ARRAY_SIZE(updates); i++) {
+ u16 mask = updates[i].mask;
+ u16 qlink_frame_type = updates[i].qlink_type;
+ bool reg;
- if (new_mask == vif->mgmt_frames_bitmask)
- return;
+ /* the ! are here due to the assoc/reassoc merge */
+ if (!(new_mask & mask) == !(old_mask & mask))
+ continue;
- switch (frame_type & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_REASSOC_REQ:
- case IEEE80211_STYPE_ASSOC_REQ:
- qlink_frame_type = QLINK_MGMT_FRAME_ASSOC_REQ;
- break;
- case IEEE80211_STYPE_AUTH:
- qlink_frame_type = QLINK_MGMT_FRAME_AUTH;
- break;
- case IEEE80211_STYPE_PROBE_REQ:
- qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ;
- break;
- case IEEE80211_STYPE_ACTION:
- qlink_frame_type = QLINK_MGMT_FRAME_ACTION;
- break;
- default:
- pr_warn("VIF%u.%u: unsupported frame type: %X\n",
- vif->mac->macid, vif->vifid,
- (frame_type & IEEE80211_FCTL_STYPE) >> 4);
- return;
- }
+ reg = new_mask & mask;
- if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) {
- pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n",
- vif->mac->macid, vif->vifid, reg ? "" : "un",
- frame_type);
- return;
+ if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg))
+ pr_warn("VIF%u.%u: failed to %sregister qlink frame type 0x%x\n",
+ vif->mac->macid, vif->vifid, reg ? "" : "un",
+ qlink_frame_type);
}
vif->mgmt_frames_bitmask = new_mask;
- pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n",
- vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type);
}
static int
@@ -1017,7 +1019,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
.change_beacon = qtnf_change_beacon,
.stop_ap = qtnf_stop_ap,
.set_wiphy_params = qtnf_set_wiphy_params,
- .mgmt_frame_register = qtnf_mgmt_frame_register,
+ .update_mgmt_frame_registrations =
+ qtnf_update_mgmt_frame_registrations,
.mgmt_tx = qtnf_mgmt_tx,
.change_station = qtnf_change_station,
.del_station = qtnf_del_station,