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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAl7L1A8ACgkQB8qZga/f l8T5RQ/9EUxFqBs0cWojwyad5nkesyl51eOnbvSCJJF14W93s2oMeikCynTPe8Vg km36041QZqGbwmU0yWC9Lmm4y3ja5qQGI+QW+vT6tutGQx6FgK5TzUfYXqiFZqf6 asqkvHpH4VqmbG1KEp0PZjIpW/OVK96pbvtXVnkrcMmjl2JjbRtAhyZQVNtt9ufJ 6wqKf8e6iYqMIInMFPLX+rl7UEknxDKVcqPbMMJmY8/iM1z9Elkg3rkRSMehC+mE 8cznZ6BsjAGCbMiA8K9fUo15lcMfZCJ1hAPzkD4TsJtMEJ0gYDo5jDB8TIpr5uoL 95OnlF8jokJIsO+1g4CyaNSQsmFIuDo84vW8LtGRu9qzTP0UwelxhjZLgE3xlP6b W+z5HomxfWkYhJhaNywLP3B1VPtJwX8dL/wpECOWHzNKXG7Rb6GqzUwaCRFb6Jjo TmFJ5wLoEZHhsXYO2dvcyTzCUCXviXvfq60a56IyCJN8wDqmcubePv0+NOHUmj3c E71NTYymM3j9agdSpXdCFLBXA1OgyIydeSNHuBlaPA4sK6tr4ikUtbOrABjYTaQz 2BB5fHEi8gs4EiHbSXqLFBot3JHljKJPsSN0wAgzQffN+6Kts9FG6HcrLsL+duDg lRdAzRrunE85S0QhsxeVIX216rX4W08sl0B1rJR+dTMX9ByblAk= =MVBJ -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
745bd6f44c
|
@ -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;
|
||||
|
|
|
@ -3249,22 +3249,19 @@ static int ath6kl_get_antenna(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
|
||||
static void ath6kl_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
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.
|
||||
* 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 = reg;
|
||||
}
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
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,
|
||||
|
|
|
@ -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 (reg)
|
||||
new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type);
|
||||
else
|
||||
new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type);
|
||||
|
||||
if (new_mask == vif->mgmt_frames_bitmask)
|
||||
if (new_mask == old_mask)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(updates); i++) {
|
||||
u16 mask = updates[i].mask;
|
||||
u16 qlink_frame_type = updates[i].qlink_type;
|
||||
bool reg;
|
||||
|
||||
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",
|
||||
/* the ! are here due to the assoc/reassoc merge */
|
||||
if (!(new_mask & mask) == !(old_mask & mask))
|
||||
continue;
|
||||
|
||||
reg = new_mask & mask;
|
||||
|
||||
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",
|
||||
frame_type);
|
||||
return;
|
||||
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,
|
||||
|
|
|
@ -3163,29 +3163,6 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
{
|
||||
struct net_device *ndev = wdev_to_ndev(wdev);
|
||||
struct adapter *adapter;
|
||||
|
||||
if (ndev == NULL)
|
||||
goto exit;
|
||||
|
||||
adapter = (struct adapter *)rtw_netdev_priv(ndev);
|
||||
|
||||
#ifdef DEBUG_CFG80211
|
||||
DBG_871X(FUNC_ADPT_FMT" frame_type:%x, reg:%d\n", FUNC_ADPT_ARG(adapter),
|
||||
frame_type, reg);
|
||||
#endif
|
||||
|
||||
if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
|
||||
return;
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PNO_SUPPORT)
|
||||
static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
|
@ -3397,7 +3374,6 @@ static struct cfg80211_ops rtw_cfg80211_ops = {
|
|||
.change_bss = cfg80211_rtw_change_bss,
|
||||
|
||||
.mgmt_tx = cfg80211_rtw_mgmt_tx,
|
||||
.mgmt_frame_register = cfg80211_rtw_mgmt_frame_register,
|
||||
|
||||
#if defined(CONFIG_PNO_SUPPORT)
|
||||
.sched_scan_start = cfg80211_rtw_sched_scan_start,
|
||||
|
|
|
@ -1217,33 +1217,31 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct mgmt_frame_regs *upd)
|
||||
{
|
||||
struct wilc *wl = wiphy_priv(wiphy);
|
||||
struct wilc_vif *vif = netdev_priv(wdev->netdev);
|
||||
u32 presp_bit = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
|
||||
u32 action_bit = BIT(IEEE80211_STYPE_ACTION >> 4);
|
||||
|
||||
if (!frame_type)
|
||||
return;
|
||||
if (wl->initialized) {
|
||||
bool prev = vif->mgmt_reg_stypes & presp_bit;
|
||||
bool now = upd->interface_stypes & presp_bit;
|
||||
|
||||
switch (frame_type) {
|
||||
case IEEE80211_STYPE_PROBE_REQ:
|
||||
vif->frame_reg[0].type = frame_type;
|
||||
vif->frame_reg[0].reg = reg;
|
||||
break;
|
||||
if (now != prev)
|
||||
wilc_frame_register(vif, IEEE80211_STYPE_PROBE_REQ, now);
|
||||
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
vif->frame_reg[1].type = frame_type;
|
||||
vif->frame_reg[1].reg = reg;
|
||||
break;
|
||||
prev = vif->mgmt_reg_stypes & action_bit;
|
||||
now = upd->interface_stypes & action_bit;
|
||||
|
||||
default:
|
||||
break;
|
||||
if (now != prev)
|
||||
wilc_frame_register(vif, IEEE80211_STYPE_ACTION, now);
|
||||
}
|
||||
|
||||
if (!wl->initialized)
|
||||
return;
|
||||
wilc_frame_register(vif, frame_type, reg);
|
||||
vif->mgmt_reg_stypes =
|
||||
upd->interface_stypes & (presp_bit | action_bit);
|
||||
}
|
||||
|
||||
static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
@ -1665,7 +1663,7 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
|
|||
.cancel_remain_on_channel = cancel_remain_on_channel,
|
||||
.mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
|
||||
.mgmt_tx = mgmt_tx,
|
||||
.mgmt_frame_register = wilc_mgmt_frame_register,
|
||||
.update_mgmt_frame_registrations = wilc_update_mgmt_frame_registrations,
|
||||
.set_power_mgmt = set_power_mgmt,
|
||||
.set_cqm_rssi_config = set_cqm_rssi_config,
|
||||
|
||||
|
|
|
@ -21,8 +21,9 @@ void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked);
|
|||
struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
|
||||
const char *name,
|
||||
struct net_device *real_dev);
|
||||
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg);
|
||||
void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
struct mgmt_frame_regs *upd);
|
||||
struct wilc_vif *wilc_get_interface(struct wilc *wl);
|
||||
struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl);
|
||||
void wlan_deinit_locks(struct wilc *wilc);
|
||||
|
|
|
@ -571,6 +571,7 @@ static int wilc_mac_open(struct net_device *ndev)
|
|||
struct wilc *wl = vif->wilc;
|
||||
unsigned char mac_add[ETH_ALEN] = {0};
|
||||
int ret = 0;
|
||||
struct mgmt_frame_regs mgmt_regs = {};
|
||||
|
||||
if (!wl || !wl->dev) {
|
||||
netdev_err(ndev, "device not ready\n");
|
||||
|
@ -602,14 +603,12 @@ static int wilc_mac_open(struct net_device *ndev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
|
||||
mgmt_regs.interface_stypes = vif->mgmt_reg_stypes;
|
||||
/* so we detect a change */
|
||||
vif->mgmt_reg_stypes = 0;
|
||||
wilc_update_mgmt_frame_registrations(vif->ndev->ieee80211_ptr->wiphy,
|
||||
vif->ndev->ieee80211_ptr,
|
||||
vif->frame_reg[0].type,
|
||||
vif->frame_reg[0].reg);
|
||||
wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
|
||||
vif->ndev->ieee80211_ptr,
|
||||
vif->frame_reg[1].type,
|
||||
vif->frame_reg[1].reg);
|
||||
&mgmt_regs);
|
||||
netif_wake_queue(ndev);
|
||||
wl->open_ifcs++;
|
||||
vif->mac_opened = 1;
|
||||
|
@ -792,12 +791,10 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
|
|||
srcu_idx = srcu_read_lock(&wilc->srcu);
|
||||
list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
|
||||
u16 type = le16_to_cpup((__le16 *)buff);
|
||||
u32 type_bit = BIT(type >> 4);
|
||||
|
||||
if (vif->priv.p2p_listen_state &&
|
||||
((type == vif->frame_reg[0].type &&
|
||||
vif->frame_reg[0].reg) ||
|
||||
(type == vif->frame_reg[1].type &&
|
||||
vif->frame_reg[1].reg)))
|
||||
vif->mgmt_reg_stypes & type_bit)
|
||||
wilc_wfi_p2p_rx(vif, buff, size);
|
||||
|
||||
if (vif->monitor_flag)
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#define PMKID_FOUND 1
|
||||
#define NUM_STA_ASSOCIATED 8
|
||||
|
||||
#define NUM_REG_FRAME 2
|
||||
|
||||
#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54
|
||||
#define DEFAULT_LINK_SPEED 72
|
||||
|
||||
|
@ -151,11 +149,6 @@ struct wilc_priv {
|
|||
u64 inc_roc_cookie;
|
||||
};
|
||||
|
||||
struct frame_reg {
|
||||
u16 type;
|
||||
bool reg;
|
||||
};
|
||||
|
||||
#define MAX_TCP_SESSION 25
|
||||
#define MAX_PENDING_ACKS 256
|
||||
|
||||
|
@ -187,7 +180,7 @@ struct wilc_vif {
|
|||
u8 iftype;
|
||||
int monitor_flag;
|
||||
int mac_opened;
|
||||
struct frame_reg frame_reg[NUM_REG_FRAME];
|
||||
u32 mgmt_reg_stypes;
|
||||
struct net_device_stats netstats;
|
||||
struct wilc *wilc;
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH
|
||||
* Copyright (c) 2018 - 2019 Intel Corporation
|
||||
* Copyright (c) 2018 - 2020 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef LINUX_IEEE80211_H
|
||||
|
@ -859,6 +859,7 @@ enum ieee80211_ht_chanwidth_values {
|
|||
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width
|
||||
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width
|
||||
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width
|
||||
* @IEEE80211_OPMODE_NOTIF_BW_160_80P80: 160 / 80+80 MHz indicator flag
|
||||
* @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask
|
||||
* (the NSS value is the value of this field + 1)
|
||||
* @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift
|
||||
|
@ -866,11 +867,12 @@ enum ieee80211_ht_chanwidth_values {
|
|||
* using a beamforming steering matrix
|
||||
*/
|
||||
enum ieee80211_vht_opmode_bits {
|
||||
IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 3,
|
||||
IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK = 0x03,
|
||||
IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ = 0,
|
||||
IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1,
|
||||
IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2,
|
||||
IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3,
|
||||
IEEE80211_OPMODE_NOTIF_BW_160_80P80 = 0x04,
|
||||
IEEE80211_OPMODE_NOTIF_RX_NSS_MASK = 0x70,
|
||||
IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4,
|
||||
IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80,
|
||||
|
@ -1065,6 +1067,7 @@ struct ieee80211_mgmt {
|
|||
/* Supported rates membership selectors */
|
||||
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
|
||||
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
|
||||
#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
|
||||
|
||||
/* mgmt header + 1 byte category code */
|
||||
#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
|
||||
|
@ -1731,6 +1734,9 @@ struct ieee80211_mu_edca_param_set {
|
|||
* @ext_nss_bw_capable: indicates whether or not the local transmitter
|
||||
* (rate scaling algorithm) can deal with the new logic
|
||||
* (dot11VHTExtendedNSSBWCapable)
|
||||
* @max_vht_nss: current maximum NSS as advertised by the STA in
|
||||
* operating mode notification, can be 0 in which case the
|
||||
* capability data will be used to derive this (from MCS support)
|
||||
*
|
||||
* Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can
|
||||
* vary for a given BW/MCS. This function parses the data.
|
||||
|
@ -1739,7 +1745,8 @@ struct ieee80211_mu_edca_param_set {
|
|||
*/
|
||||
int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
||||
enum ieee80211_vht_chanwidth bw,
|
||||
int mcs, bool ext_nss_bw_capable);
|
||||
int mcs, bool ext_nss_bw_capable,
|
||||
unsigned int max_vht_nss);
|
||||
|
||||
/* 802.11ax HE MAC capabilities */
|
||||
#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01
|
||||
|
@ -3323,6 +3330,16 @@ static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size)
|
|||
#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
|
||||
#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
|
||||
|
||||
/* convert frequencies */
|
||||
#define MHZ_TO_KHZ(freq) ((freq) * 1000)
|
||||
#define KHZ_TO_MHZ(freq) ((freq) / 1000)
|
||||
|
||||
/* convert powers */
|
||||
#define DBI_TO_MBI(gain) ((gain) * 100)
|
||||
#define MBI_TO_DBI(gain) ((gain) / 100)
|
||||
#define DBM_TO_MBM(gain) ((gain) * 100)
|
||||
#define MBM_TO_DBM(gain) ((gain) / 100)
|
||||
|
||||
/**
|
||||
* ieee80211_action_contains_tpc - checks if the frame contains TPC element
|
||||
* @skb: the skb containing the frame, length will be checked
|
||||
|
|
|
@ -128,6 +128,7 @@ enum ieee80211_channel_flags {
|
|||
* with cfg80211.
|
||||
*
|
||||
* @center_freq: center frequency in MHz
|
||||
* @freq_offset: offset from @center_freq, in KHz
|
||||
* @hw_value: hardware-specific value for the channel
|
||||
* @flags: channel flags from &enum ieee80211_channel_flags.
|
||||
* @orig_flags: channel flags at registration time, used by regulatory
|
||||
|
@ -149,6 +150,7 @@ enum ieee80211_channel_flags {
|
|||
struct ieee80211_channel {
|
||||
enum nl80211_band band;
|
||||
u32 center_freq;
|
||||
u16 freq_offset;
|
||||
u16 hw_value;
|
||||
u32 flags;
|
||||
int max_antenna_gain;
|
||||
|
@ -617,6 +619,7 @@ struct key_params {
|
|||
* If edmg is requested (i.e. the .channels member is non-zero),
|
||||
* chan will define the primary channel and all other
|
||||
* parameters are ignored.
|
||||
* @freq1_offset: offset from @center_freq1, in KHz
|
||||
*/
|
||||
struct cfg80211_chan_def {
|
||||
struct ieee80211_channel *chan;
|
||||
|
@ -624,6 +627,7 @@ struct cfg80211_chan_def {
|
|||
u32 center_freq1;
|
||||
u32 center_freq2;
|
||||
struct ieee80211_edmg edmg;
|
||||
u16 freq1_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -713,6 +717,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
|
|||
return (chandef1->chan == chandef2->chan &&
|
||||
chandef1->width == chandef2->width &&
|
||||
chandef1->center_freq1 == chandef2->center_freq1 &&
|
||||
chandef1->freq1_offset == chandef2->freq1_offset &&
|
||||
chandef1->center_freq2 == chandef2->center_freq2);
|
||||
}
|
||||
|
||||
|
@ -1054,6 +1059,7 @@ enum cfg80211_ap_settings_flags {
|
|||
* @ht_required: stations must support HT
|
||||
* @vht_required: stations must support VHT
|
||||
* @twt_responder: Enable Target Wait Time
|
||||
* @he_required: stations must support HE
|
||||
* @flags: flags, as defined in enum cfg80211_ap_settings_flags
|
||||
* @he_obss_pd: OBSS Packet Detection settings
|
||||
* @he_bss_color: BSS Color settings
|
||||
|
@ -1083,7 +1089,7 @@ struct cfg80211_ap_settings {
|
|||
const struct ieee80211_vht_cap *vht_cap;
|
||||
const struct ieee80211_he_cap_elem *he_cap;
|
||||
const struct ieee80211_he_operation *he_oper;
|
||||
bool ht_required, vht_required;
|
||||
bool ht_required, vht_required, he_required;
|
||||
bool twt_responder;
|
||||
u32 flags;
|
||||
struct ieee80211_he_obss_pd he_obss_pd;
|
||||
|
@ -3384,6 +3390,21 @@ struct cfg80211_update_owe_info {
|
|||
size_t ie_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mgmt_frame_regs - management frame registrations data
|
||||
* @global_stypes: bitmap of management frame subtypes registered
|
||||
* for the entire device
|
||||
* @interface_stypes: bitmap of management frame subtypes registered
|
||||
* for the given interface
|
||||
* @global_mcast_rx: mcast RX is needed globally for these subtypes
|
||||
* @interface_mcast_stypes: mcast RX is needed on this interface
|
||||
* for these subtypes
|
||||
*/
|
||||
struct mgmt_frame_regs {
|
||||
u32 global_stypes, interface_stypes;
|
||||
u32 global_mcast_stypes, interface_mcast_stypes;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ops - backend description for wireless configuration
|
||||
*
|
||||
|
@ -3608,8 +3629,8 @@ struct cfg80211_update_owe_info {
|
|||
* The driver should not call cfg80211_sched_scan_stopped() for a requested
|
||||
* stop (when this method returns 0).
|
||||
*
|
||||
* @mgmt_frame_register: Notify driver that a management frame type was
|
||||
* registered. The callback is allowed to sleep.
|
||||
* @update_mgmt_frame_registrations: Notify the driver that management frame
|
||||
* registrations were updated. The callback is allowed to sleep.
|
||||
*
|
||||
* @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
|
||||
* Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
|
||||
|
@ -3932,9 +3953,9 @@ struct cfg80211_ops {
|
|||
struct net_device *dev,
|
||||
u32 rate, u32 pkts, u32 intvl);
|
||||
|
||||
void (*mgmt_frame_register)(struct wiphy *wiphy,
|
||||
void (*update_mgmt_frame_registrations)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg);
|
||||
struct mgmt_frame_regs *upd);
|
||||
|
||||
int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
|
||||
int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
|
||||
|
@ -5015,6 +5036,7 @@ struct cfg80211_cqm_config;
|
|||
* by cfg80211 on change_interface
|
||||
* @mgmt_registrations: list of registrations for management frames
|
||||
* @mgmt_registrations_lock: lock for the list
|
||||
* @mgmt_registrations_update_wk: update work to defer from atomic context
|
||||
* @mtx: mutex used to lock data in this struct, may be used by drivers
|
||||
* and some API functions require it held
|
||||
* @beacon_interval: beacon interval used on this device for transmitting
|
||||
|
@ -5045,6 +5067,8 @@ struct cfg80211_cqm_config;
|
|||
* @pmsr_list: (private) peer measurement requests
|
||||
* @pmsr_lock: (private) peer measurements requests/results lock
|
||||
* @pmsr_free_wk: (private) peer measurements cleanup work
|
||||
* @unprot_beacon_reported: (private) timestamp of last
|
||||
* unprotected beacon report
|
||||
*/
|
||||
struct wireless_dev {
|
||||
struct wiphy *wiphy;
|
||||
|
@ -5058,6 +5082,7 @@ struct wireless_dev {
|
|||
|
||||
struct list_head mgmt_registrations;
|
||||
spinlock_t mgmt_registrations_lock;
|
||||
struct work_struct mgmt_registrations_update_wk;
|
||||
|
||||
struct mutex mtx;
|
||||
|
||||
|
@ -5121,6 +5146,8 @@ struct wireless_dev {
|
|||
struct list_head pmsr_list;
|
||||
spinlock_t pmsr_lock;
|
||||
struct work_struct pmsr_free_wk;
|
||||
|
||||
unsigned long unprot_beacon_reported;
|
||||
};
|
||||
|
||||
static inline u8 *wdev_address(struct wireless_dev *wdev)
|
||||
|
@ -5155,30 +5182,92 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
|
|||
* cfg80211 offers a number of utility functions that can be useful.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ieee80211_channel_equal - compare two struct ieee80211_channel
|
||||
*
|
||||
* @a: 1st struct ieee80211_channel
|
||||
* @b: 2nd struct ieee80211_channel
|
||||
* Return: true if center frequency of @a == @b
|
||||
*/
|
||||
static inline bool
|
||||
ieee80211_channel_equal(struct ieee80211_channel *a,
|
||||
struct ieee80211_channel *b)
|
||||
{
|
||||
return (a->center_freq == b->center_freq &&
|
||||
a->freq_offset == b->freq_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_channel_to_khz - convert ieee80211_channel to frequency in KHz
|
||||
* @chan: struct ieee80211_channel to convert
|
||||
* Return: The corresponding frequency (in KHz)
|
||||
*/
|
||||
static inline u32
|
||||
ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
|
||||
{
|
||||
return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_channel_to_freq_khz - convert channel number to frequency
|
||||
* @chan: channel number
|
||||
* @band: band, necessary due to channel number overlap
|
||||
* Return: The corresponding frequency (in KHz), or 0 if the conversion failed.
|
||||
*/
|
||||
u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band);
|
||||
|
||||
/**
|
||||
* ieee80211_channel_to_frequency - convert channel number to frequency
|
||||
* @chan: channel number
|
||||
* @band: band, necessary due to channel number overlap
|
||||
* Return: The corresponding frequency (in MHz), or 0 if the conversion failed.
|
||||
*/
|
||||
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band);
|
||||
static inline int
|
||||
ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
|
||||
{
|
||||
return KHZ_TO_MHZ(ieee80211_channel_to_freq_khz(chan, band));
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_freq_khz_to_channel - convert frequency to channel number
|
||||
* @freq: center frequency in KHz
|
||||
* Return: The corresponding channel, or 0 if the conversion failed.
|
||||
*/
|
||||
int ieee80211_freq_khz_to_channel(u32 freq);
|
||||
|
||||
/**
|
||||
* ieee80211_frequency_to_channel - convert frequency to channel number
|
||||
* @freq: center frequency
|
||||
* @freq: center frequency in MHz
|
||||
* Return: The corresponding channel, or 0 if the conversion failed.
|
||||
*/
|
||||
int ieee80211_frequency_to_channel(int freq);
|
||||
static inline int
|
||||
ieee80211_frequency_to_channel(int freq)
|
||||
{
|
||||
return ieee80211_freq_khz_to_channel(MHZ_TO_KHZ(freq));
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_get_channel_khz - get channel struct from wiphy for specified
|
||||
* frequency
|
||||
* @wiphy: the struct wiphy to get the channel for
|
||||
* @freq: the center frequency (in KHz) of the channel
|
||||
* Return: The channel struct from @wiphy at @freq.
|
||||
*/
|
||||
struct ieee80211_channel *
|
||||
ieee80211_get_channel_khz(struct wiphy *wiphy, u32 freq);
|
||||
|
||||
/**
|
||||
* ieee80211_get_channel - get channel struct from wiphy for specified frequency
|
||||
*
|
||||
* @wiphy: the struct wiphy to get the channel for
|
||||
* @freq: the center frequency of the channel
|
||||
*
|
||||
* @freq: the center frequency (in MHz) of the channel
|
||||
* Return: The channel struct from @wiphy at @freq.
|
||||
*/
|
||||
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq);
|
||||
static inline struct ieee80211_channel *
|
||||
ieee80211_get_channel(struct wiphy *wiphy, int freq)
|
||||
{
|
||||
return ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(freq));
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_get_response_rate - get basic rate for a given rate
|
||||
|
@ -6135,12 +6224,16 @@ void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
|
|||
/**
|
||||
* cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
|
||||
* @dev: network device
|
||||
* @buf: deauthentication frame (header + body)
|
||||
* @buf: received management frame (header + body)
|
||||
* @len: length of the frame data
|
||||
*
|
||||
* This function is called whenever a received deauthentication or dissassoc
|
||||
* frame has been dropped in station mode because of MFP being used but the
|
||||
* frame was not protected. This function may sleep.
|
||||
* frame was not protected. This is also used to notify reception of a Beacon
|
||||
* frame that was dropped because it did not include a valid MME MIC while
|
||||
* beacon protection was enabled (BIGTK configured in station mode).
|
||||
*
|
||||
* This function may sleep.
|
||||
*/
|
||||
void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev,
|
||||
const u8 *buf, size_t len);
|
||||
|
@ -7202,6 +7295,19 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
|
|||
bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
|
||||
u8 *op_class);
|
||||
|
||||
/**
|
||||
* ieee80211_chandef_to_khz - convert chandef to frequency in KHz
|
||||
*
|
||||
* @chandef: the chandef to convert
|
||||
*
|
||||
* Returns the center frequency of chandef (1st segment) in KHz.
|
||||
*/
|
||||
static inline u32
|
||||
ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
return MHZ_TO_KHZ(chandef->center_freq1) + chandef->freq1_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* cfg80211_tdls_oper_request - request userspace to perform TDLS operation
|
||||
* @dev: the device on which the operation is requested
|
||||
|
|
|
@ -508,6 +508,7 @@ struct ieee80211_ftm_responder_params {
|
|||
* mode only, set if the AP advertises TWT responder role)
|
||||
* @twt_responder: does this BSS support TWT requester (relevant for managed
|
||||
* mode only, set if the AP advertises TWT responder role)
|
||||
* @twt_protected: does this BSS support protected TWT frames
|
||||
* @assoc: association status
|
||||
* @ibss_joined: indicates whether this station is part of an IBSS
|
||||
* or not
|
||||
|
@ -603,7 +604,7 @@ struct ieee80211_ftm_responder_params {
|
|||
* nontransmitted BSSIDs
|
||||
* @profile_periodicity: the least number of beacon frames need to be received
|
||||
* in order to discover all the nontransmitted BSSIDs in the set.
|
||||
* @he_operation: HE operation information of the AP we are connected to
|
||||
* @he_oper: HE operation information of the AP we are connected to
|
||||
* @he_obss_pd: OBSS Packet Detection parameters.
|
||||
* @he_bss_color: BSS coloring settings, if BSS supports HE
|
||||
*/
|
||||
|
@ -618,6 +619,7 @@ struct ieee80211_bss_conf {
|
|||
bool he_support;
|
||||
bool twt_requester;
|
||||
bool twt_responder;
|
||||
bool twt_protected;
|
||||
/* association related data */
|
||||
bool assoc, ibss_joined;
|
||||
bool ibss_creator;
|
||||
|
@ -666,7 +668,10 @@ struct ieee80211_bss_conf {
|
|||
u8 bssid_indicator;
|
||||
bool ema_ap;
|
||||
u8 profile_periodicity;
|
||||
struct ieee80211_he_operation he_operation;
|
||||
struct {
|
||||
u32 params;
|
||||
u16 nss_set;
|
||||
} he_oper;
|
||||
struct ieee80211_he_obss_pd he_obss_pd;
|
||||
struct cfg80211_he_bss_color he_bss_color;
|
||||
};
|
||||
|
@ -818,6 +823,8 @@ enum mac80211_tx_info_flags {
|
|||
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
|
||||
* @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
|
||||
* @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup
|
||||
* @IEEE80211_TX_CTRL_HW_80211_ENCAP: This frame uses hardware encapsulation
|
||||
* (header conversion)
|
||||
*
|
||||
* These flags are used in tx_info->control.flags.
|
||||
*/
|
||||
|
@ -1333,6 +1340,7 @@ enum mac80211_rx_encoding {
|
|||
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
|
||||
* This field must be set for management frames, but isn't strictly needed
|
||||
* for data (other) frames - for those it only affects radiotap reporting.
|
||||
* @freq_offset: @freq has a positive offset of 500Khz.
|
||||
* @signal: signal strength when receiving this frame, either in dBm, in dB or
|
||||
* unspecified depending on the hardware capabilities flags
|
||||
* @IEEE80211_HW_SIGNAL_*
|
||||
|
@ -1363,7 +1371,7 @@ struct ieee80211_rx_status {
|
|||
u32 device_timestamp;
|
||||
u32 ampdu_reference;
|
||||
u32 flag;
|
||||
u16 freq;
|
||||
u16 freq: 13, freq_offset: 1;
|
||||
u8 enc_flags;
|
||||
u8 encoding:2, bw:3, he_ru:3;
|
||||
u8 he_gi:2, he_dcm:1;
|
||||
|
@ -1379,6 +1387,13 @@ struct ieee80211_rx_status {
|
|||
u8 zero_length_psdu_type;
|
||||
};
|
||||
|
||||
static inline u32
|
||||
ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
return MHZ_TO_KHZ(rx_status->freq) +
|
||||
(rx_status->freq_offset ? 500 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ieee80211_vendor_radiotap - vendor radiotap data information
|
||||
* @present: presence bitmap for this vendor namespace
|
||||
|
@ -1620,6 +1635,8 @@ enum ieee80211_vif_flags {
|
|||
* monitor interface (if that is requested.)
|
||||
* @probe_req_reg: probe requests should be reported to mac80211 for this
|
||||
* interface.
|
||||
* @rx_mcast_action_reg: multicast Action frames should be reported to mac80211
|
||||
* for this interface.
|
||||
* @drv_priv: data area for driver use, will always be aligned to
|
||||
* sizeof(void \*).
|
||||
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
|
||||
|
@ -1647,7 +1664,8 @@ struct ieee80211_vif {
|
|||
struct dentry *debugfs_dir;
|
||||
#endif
|
||||
|
||||
unsigned int probe_req_reg;
|
||||
bool probe_req_reg;
|
||||
bool rx_mcast_action_reg;
|
||||
|
||||
bool txqs_stopped[IEEE80211_NUM_ACS];
|
||||
|
||||
|
@ -3091,6 +3109,8 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
|||
* @FIF_PSPOLL: pass PS Poll frames
|
||||
*
|
||||
* @FIF_PROBE_REQ: pass probe request frames
|
||||
*
|
||||
* @FIF_MCAST_ACTION: pass multicast Action frames
|
||||
*/
|
||||
enum ieee80211_filter_flags {
|
||||
FIF_ALLMULTI = 1<<1,
|
||||
|
@ -3101,6 +3121,7 @@ enum ieee80211_filter_flags {
|
|||
FIF_OTHER_BSS = 1<<6,
|
||||
FIF_PSPOLL = 1<<7,
|
||||
FIF_PROBE_REQ = 1<<8,
|
||||
FIF_MCAST_ACTION = 1<<9,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -3117,7 +3138,10 @@ enum ieee80211_filter_flags {
|
|||
* @IEEE80211_AMPDU_RX_START: start RX aggregation
|
||||
* @IEEE80211_AMPDU_RX_STOP: stop RX aggregation
|
||||
* @IEEE80211_AMPDU_TX_START: start TX aggregation, the driver must either
|
||||
* call ieee80211_start_tx_ba_cb_irqsafe() or return the special
|
||||
* call ieee80211_start_tx_ba_cb_irqsafe() or
|
||||
* call ieee80211_start_tx_ba_cb_irqsafe() with status
|
||||
* %IEEE80211_AMPDU_TX_START_DELAY_ADDBA to delay addba after
|
||||
* ieee80211_start_tx_ba_cb_irqsafe is called, or just return the special
|
||||
* status %IEEE80211_AMPDU_TX_START_IMMEDIATE.
|
||||
* @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational
|
||||
* @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
|
||||
|
@ -3143,6 +3167,7 @@ enum ieee80211_ampdu_mlme_action {
|
|||
};
|
||||
|
||||
#define IEEE80211_AMPDU_TX_START_IMMEDIATE 1
|
||||
#define IEEE80211_AMPDU_TX_START_DELAY_ADDBA 2
|
||||
|
||||
/**
|
||||
* struct ieee80211_ampdu_params - AMPDU action parameters
|
||||
|
|
|
@ -231,13 +231,6 @@ struct ieee80211_regdomain {
|
|||
struct ieee80211_reg_rule reg_rules[];
|
||||
};
|
||||
|
||||
#define MHZ_TO_KHZ(freq) ((freq) * 1000)
|
||||
#define KHZ_TO_MHZ(freq) ((freq) / 1000)
|
||||
#define DBI_TO_MBI(gain) ((gain) * 100)
|
||||
#define MBI_TO_DBI(gain) ((gain) / 100)
|
||||
#define DBM_TO_MBM(gain) ((gain) * 100)
|
||||
#define MBM_TO_DBM(gain) ((gain) / 100)
|
||||
|
||||
#define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \
|
||||
{ \
|
||||
.freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
|
||||
|
|
|
@ -687,6 +687,10 @@
|
|||
* four bytes for vendor frames including the OUI. The registration
|
||||
* cannot be dropped, but is removed automatically when the netlink
|
||||
* socket is closed. Multiple registrations can be made.
|
||||
* The %NL80211_ATTR_RECEIVE_MULTICAST flag attribute can be given if
|
||||
* %NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS is available, in which
|
||||
* case the registration can also be modified to include/exclude the
|
||||
* flag, rather than requiring unregistration to change it.
|
||||
* @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
|
||||
* backward compatibility
|
||||
* @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
|
||||
|
@ -1151,6 +1155,11 @@
|
|||
* @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
|
||||
* is passed using %NL80211_ATTR_TID_CONFIG attribute.
|
||||
*
|
||||
* @NL80211_CMD_UNPROT_BEACON: Unprotected or incorrectly protected Beacon
|
||||
* frame. This event is used to indicate that a received Beacon frame was
|
||||
* dropped because it did not include a valid MME MIC while beacon
|
||||
* protection was enabled (BIGTK configured in station mode).
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -1377,6 +1386,8 @@ enum nl80211_commands {
|
|||
|
||||
NL80211_CMD_SET_TID_CONFIG,
|
||||
|
||||
NL80211_CMD_UNPROT_BEACON,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -2470,6 +2481,9 @@ enum nl80211_commands {
|
|||
* no roaming occurs between the reauth threshold and PMK expiration,
|
||||
* disassociation is still forced.
|
||||
*
|
||||
* @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the
|
||||
* %NL80211_CMD_REGISTER_FRAME command, see the description there.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -2945,6 +2959,8 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_PMK_LIFETIME,
|
||||
NL80211_ATTR_PMK_REAUTH_THRESHOLD,
|
||||
|
||||
NL80211_ATTR_RECEIVE_MULTICAST,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -5674,6 +5690,8 @@ enum nl80211_feature_flags {
|
|||
*
|
||||
* @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
|
||||
* and can receive key configuration for BIGTK using key indexes 6 and 7.
|
||||
* @NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT: The driver supports Beacon
|
||||
* protection as a client only and cannot transmit protected beacons.
|
||||
*
|
||||
* @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
|
||||
* forwarding of preauth frames over the control port. They are then
|
||||
|
@ -5684,6 +5702,9 @@ enum nl80211_feature_flags {
|
|||
* @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
|
||||
* in IBSS mode, essentially by dropping their state.
|
||||
*
|
||||
* @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations
|
||||
* are possible for multicast frames and those will be reported properly.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
|
@ -5735,6 +5756,8 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH,
|
||||
NL80211_EXT_FEATURE_PROTECTED_TWT,
|
||||
NL80211_EXT_FEATURE_DEL_IBSS_STA,
|
||||
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
|
||||
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2007-2010, Intel Corporation
|
||||
* Copyright(c) 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
* Copyright (C) 2018 - 2020 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
|
@ -448,66 +448,14 @@ static void sta_addba_resp_timer_expired(struct timer_list *t)
|
|||
ieee80211_stop_tx_ba_session(&sta->sta, tid);
|
||||
}
|
||||
|
||||
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||
static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
|
||||
struct tid_ampdu_tx *tid_tx)
|
||||
{
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_ampdu_params params = {
|
||||
.sta = &sta->sta,
|
||||
.action = IEEE80211_AMPDU_TX_START,
|
||||
.tid = tid,
|
||||
.buf_size = 0,
|
||||
.amsdu = false,
|
||||
.timeout = 0,
|
||||
};
|
||||
int ret;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
u8 tid = tid_tx->tid;
|
||||
u16 buf_size;
|
||||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
/*
|
||||
* Start queuing up packets for this aggregation session.
|
||||
* We're going to release them once the driver is OK with
|
||||
* that.
|
||||
*/
|
||||
clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
|
||||
|
||||
ieee80211_agg_stop_txq(sta, tid);
|
||||
|
||||
/*
|
||||
* Make sure no packets are being processed. This ensures that
|
||||
* we have a valid starting sequence number and that in-flight
|
||||
* packets have been flushed out and no packets for this TID
|
||||
* will go into the driver during the ampdu_action call.
|
||||
*/
|
||||
synchronize_net();
|
||||
|
||||
params.ssn = sta->tid_seq[tid] >> 4;
|
||||
ret = drv_ampdu_action(local, sdata, ¶ms);
|
||||
if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
|
||||
/*
|
||||
* We didn't send the request yet, so don't need to check
|
||||
* here if we already got a response, just mark as driver
|
||||
* ready immediately.
|
||||
*/
|
||||
set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state);
|
||||
} else if (ret) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - HW unavailable for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
spin_lock_bh(&sta->lock);
|
||||
ieee80211_agg_splice_packets(sdata, tid_tx, tid);
|
||||
ieee80211_assign_tid_tx(sta, tid, NULL);
|
||||
ieee80211_agg_splice_finish(sdata, tid);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
ieee80211_agg_start_txq(sta, tid, false);
|
||||
|
||||
kfree_rcu(tid_tx, rcu_head);
|
||||
return;
|
||||
}
|
||||
|
||||
/* activate the timer for the recipient's addBA response */
|
||||
mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
|
||||
ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n",
|
||||
|
@ -532,8 +480,75 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
|||
|
||||
/* send AddBA request */
|
||||
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
|
||||
tid_tx->dialog_token, params.ssn,
|
||||
tid_tx->dialog_token,
|
||||
sta->tid_seq[tid] >> 4,
|
||||
buf_size, tid_tx->timeout);
|
||||
|
||||
WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
|
||||
}
|
||||
|
||||
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||
{
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_ampdu_params params = {
|
||||
.sta = &sta->sta,
|
||||
.action = IEEE80211_AMPDU_TX_START,
|
||||
.tid = tid,
|
||||
.buf_size = 0,
|
||||
.amsdu = false,
|
||||
.timeout = 0,
|
||||
};
|
||||
int ret;
|
||||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
/*
|
||||
* Start queuing up packets for this aggregation session.
|
||||
* We're going to release them once the driver is OK with
|
||||
* that.
|
||||
*/
|
||||
clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
|
||||
|
||||
ieee80211_agg_stop_txq(sta, tid);
|
||||
|
||||
/*
|
||||
* Make sure no packets are being processed. This ensures that
|
||||
* we have a valid starting sequence number and that in-flight
|
||||
* packets have been flushed out and no packets for this TID
|
||||
* will go into the driver during the ampdu_action call.
|
||||
*/
|
||||
synchronize_net();
|
||||
|
||||
params.ssn = sta->tid_seq[tid] >> 4;
|
||||
ret = drv_ampdu_action(local, sdata, ¶ms);
|
||||
if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
|
||||
return;
|
||||
} else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
|
||||
/*
|
||||
* We didn't send the request yet, so don't need to check
|
||||
* here if we already got a response, just mark as driver
|
||||
* ready immediately.
|
||||
*/
|
||||
set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state);
|
||||
} else if (ret) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - HW unavailable for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
spin_lock_bh(&sta->lock);
|
||||
ieee80211_agg_splice_packets(sdata, tid_tx, tid);
|
||||
ieee80211_assign_tid_tx(sta, tid, NULL);
|
||||
ieee80211_agg_splice_finish(sdata, tid);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
ieee80211_agg_start_txq(sta, tid, false);
|
||||
|
||||
kfree_rcu(tid_tx, rcu_head);
|
||||
return;
|
||||
}
|
||||
|
||||
ieee80211_send_addba_with_timeout(sta, tid_tx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -754,6 +769,12 @@ void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
|
|||
if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
|
||||
return;
|
||||
|
||||
if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) {
|
||||
ieee80211_send_addba_with_timeout(sta, tid_tx);
|
||||
/* RESPONSE_RECEIVED state whould trigger the flow again */
|
||||
return;
|
||||
}
|
||||
|
||||
if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
|
||||
ieee80211_agg_tx_operational(local, sta, tid);
|
||||
}
|
||||
|
|
|
@ -994,7 +994,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
BSS_CHANGED_TWT |
|
||||
BSS_CHANGED_HE_OBSS_PD |
|
||||
BSS_CHANGED_HE_BSS_COLOR;
|
||||
int err;
|
||||
int i, err;
|
||||
int prev_beacon_int;
|
||||
|
||||
old = sdata_dereference(sdata->u.ap.beacon, sdata);
|
||||
|
@ -1085,6 +1085,17 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
|
||||
IEEE80211_P2P_OPPPS_ENABLE_BIT;
|
||||
|
||||
sdata->beacon_rate_set = false;
|
||||
if (wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
|
||||
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
||||
sdata->beacon_rateidx_mask[i] =
|
||||
params->beacon_rate.control[i].legacy;
|
||||
if (sdata->beacon_rateidx_mask[i])
|
||||
sdata->beacon_rate_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL);
|
||||
if (err < 0) {
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
|
@ -1189,6 +1200,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
|||
ieee80211_free_keys(sdata, true);
|
||||
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
sdata->beacon_rate_set = false;
|
||||
sdata->vif.bss_conf.ssid_len = 0;
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
|
@ -1949,6 +1961,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
|
|||
const u8 *old_ie;
|
||||
struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
|
||||
struct ieee80211_sub_if_data, u.mesh);
|
||||
int i;
|
||||
|
||||
/* allocate information elements */
|
||||
new_ie = NULL;
|
||||
|
@ -1987,6 +2000,17 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
|
|||
sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
|
||||
sdata->vif.bss_conf.dtim_period = setup->dtim_period;
|
||||
|
||||
sdata->beacon_rate_set = false;
|
||||
if (wiphy_ext_feature_isset(sdata->local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
|
||||
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
||||
sdata->beacon_rateidx_mask[i] =
|
||||
setup->beacon_rate.control[i].legacy;
|
||||
if (sdata->beacon_rateidx_mask[i])
|
||||
sdata->beacon_rate_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3287,6 +3311,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (params->chandef.chan->freq_offset) {
|
||||
/* this may work, but is untested */
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
chanctx = container_of(conf, struct ieee80211_chanctx, conf);
|
||||
|
||||
ch_switch.timestamp = 0;
|
||||
|
@ -3398,41 +3428,43 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
|
||||
static void
|
||||
ieee80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
struct mgmt_frame_regs *upd)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
u32 preq_mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
|
||||
u32 action_mask = BIT(IEEE80211_STYPE_ACTION >> 4);
|
||||
bool global_change, intf_change;
|
||||
|
||||
switch (frame_type) {
|
||||
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
|
||||
if (reg) {
|
||||
local->probe_req_reg++;
|
||||
sdata->vif.probe_req_reg++;
|
||||
} else {
|
||||
if (local->probe_req_reg)
|
||||
local->probe_req_reg--;
|
||||
global_change =
|
||||
(local->probe_req_reg != !!(upd->global_stypes & preq_mask)) ||
|
||||
(local->rx_mcast_action_reg !=
|
||||
!!(upd->global_mcast_stypes & action_mask));
|
||||
local->probe_req_reg = upd->global_stypes & preq_mask;
|
||||
local->rx_mcast_action_reg = upd->global_mcast_stypes & action_mask;
|
||||
|
||||
if (sdata->vif.probe_req_reg)
|
||||
sdata->vif.probe_req_reg--;
|
||||
}
|
||||
intf_change = (sdata->vif.probe_req_reg !=
|
||||
!!(upd->interface_stypes & preq_mask)) ||
|
||||
(sdata->vif.rx_mcast_action_reg !=
|
||||
!!(upd->interface_mcast_stypes & action_mask));
|
||||
sdata->vif.probe_req_reg = upd->interface_stypes & preq_mask;
|
||||
sdata->vif.rx_mcast_action_reg =
|
||||
upd->interface_mcast_stypes & action_mask;
|
||||
|
||||
if (!local->open_count)
|
||||
break;
|
||||
return;
|
||||
|
||||
if (sdata->vif.probe_req_reg == 1)
|
||||
drv_config_iface_filter(local, sdata, FIF_PROBE_REQ,
|
||||
FIF_PROBE_REQ);
|
||||
else if (sdata->vif.probe_req_reg == 0)
|
||||
drv_config_iface_filter(local, sdata, 0,
|
||||
if (intf_change && ieee80211_sdata_running(sdata))
|
||||
drv_config_iface_filter(local, sdata,
|
||||
sdata->vif.probe_req_reg ?
|
||||
FIF_PROBE_REQ : 0,
|
||||
FIF_PROBE_REQ);
|
||||
|
||||
if (global_change)
|
||||
ieee80211_configure_filter(local);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
|
||||
|
@ -4017,7 +4049,8 @@ const struct cfg80211_ops mac80211_config_ops = {
|
|||
.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
|
||||
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
|
||||
.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
|
||||
.mgmt_frame_register = ieee80211_mgmt_frame_register,
|
||||
.update_mgmt_frame_registrations =
|
||||
ieee80211_update_mgmt_frame_registrations,
|
||||
.set_antenna = ieee80211_set_antenna,
|
||||
.get_antenna = ieee80211_get_antenna,
|
||||
.set_rekey_data = ieee80211_set_rekey_data,
|
||||
|
|
|
@ -533,6 +533,7 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
|
|||
struct cfg80211_chan_def *chandef = &local->_oper_chandef;
|
||||
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
|
||||
chandef->center_freq1 = chandef->chan->center_freq;
|
||||
chandef->freq1_offset = chandef->chan->freq_offset;
|
||||
chandef->center_freq2 = 0;
|
||||
|
||||
/* NOTE: Disabling radar is only valid here for
|
||||
|
|
|
@ -236,7 +236,7 @@ IEEE80211_IF_FILE_R(hw_queues);
|
|||
|
||||
/* STA attributes */
|
||||
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
|
||||
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
|
||||
IEEE80211_IF_FILE(aid, vif.bss_conf.aid, DEC);
|
||||
IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
|
||||
|
||||
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
@ -57,17 +57,14 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
void
|
||||
ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
|
||||
const struct ieee80211_he_operation *he_op_ie_elem)
|
||||
const struct ieee80211_he_operation *he_op_ie)
|
||||
{
|
||||
struct ieee80211_he_operation *he_operation =
|
||||
&vif->bss_conf.he_operation;
|
||||
|
||||
if (!he_op_ie_elem) {
|
||||
memset(he_operation, 0, sizeof(*he_operation));
|
||||
memset(&vif->bss_conf.he_oper, 0, sizeof(vif->bss_conf.he_oper));
|
||||
if (!he_op_ie)
|
||||
return;
|
||||
}
|
||||
|
||||
vif->bss_conf.he_operation = *he_op_ie_elem;
|
||||
vif->bss_conf.he_oper.params = __le32_to_cpu(he_op_ie->he_oper_params);
|
||||
vif->bss_conf.he_oper.nss_set = __le16_to_cpu(he_op_ie->he_mcs_nss_set);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1758,6 +1758,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|||
int i;
|
||||
int ret;
|
||||
|
||||
if (params->chandef.chan->freq_offset) {
|
||||
/* this may work, but is untested */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
|
||||
¶ms->chandef,
|
||||
sdata->wdev.iftype);
|
||||
|
|
|
@ -450,8 +450,6 @@ struct ieee80211_if_managed {
|
|||
|
||||
u8 bssid[ETH_ALEN] __aligned(2);
|
||||
|
||||
u16 aid;
|
||||
|
||||
bool powersave; /* powersave requested for this iface */
|
||||
bool broken_ap; /* AP is broken -- turn off powersave */
|
||||
bool have_beacon;
|
||||
|
@ -964,6 +962,10 @@ struct ieee80211_sub_if_data {
|
|||
bool rc_has_vht_mcs_mask[NUM_NL80211_BANDS];
|
||||
u16 rc_rateidx_vht_mcs_mask[NUM_NL80211_BANDS][NL80211_VHT_NSS_MAX];
|
||||
|
||||
/* Beacon frame (non-MCS) rate (as a bitmap) */
|
||||
u32 beacon_rateidx_mask[NUM_NL80211_BANDS];
|
||||
bool beacon_rate_set;
|
||||
|
||||
union {
|
||||
struct ieee80211_if_ap ap;
|
||||
struct ieee80211_if_wds wds;
|
||||
|
@ -1169,7 +1171,8 @@ struct ieee80211_local {
|
|||
/* number of interfaces with corresponding FIF_ flags */
|
||||
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
|
||||
fif_probe_req;
|
||||
int probe_req_reg;
|
||||
bool probe_req_reg;
|
||||
bool rx_mcast_action_reg;
|
||||
unsigned int filter_flags; /* FIF_* */
|
||||
|
||||
bool wiphy_ciphers_allocated;
|
||||
|
|
|
@ -644,6 +644,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
local->fif_probe_req++;
|
||||
}
|
||||
|
||||
if (sdata->vif.probe_req_reg)
|
||||
drv_config_iface_filter(local, sdata,
|
||||
FIF_PROBE_REQ,
|
||||
FIF_PROBE_REQ);
|
||||
|
||||
if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
|
||||
sdata->vif.type != NL80211_IFTYPE_NAN)
|
||||
changed |= ieee80211_reset_erp_info(sdata);
|
||||
|
|
|
@ -64,6 +64,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
|
|||
if (local->fif_pspoll)
|
||||
new_flags |= FIF_PSPOLL;
|
||||
|
||||
if (local->rx_mcast_action_reg)
|
||||
new_flags |= FIF_MCAST_ACTION;
|
||||
|
||||
spin_lock_bh(&local->filter_lock);
|
||||
changed_flags = local->filter_flags ^ new_flags;
|
||||
|
||||
|
@ -104,13 +107,15 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
|
|||
chandef.chan = local->tmp_channel;
|
||||
chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
|
||||
chandef.center_freq1 = chandef.chan->center_freq;
|
||||
chandef.freq1_offset = chandef.chan->freq_offset;
|
||||
} else
|
||||
chandef = local->_oper_chandef;
|
||||
|
||||
WARN(!cfg80211_chandef_valid(&chandef),
|
||||
"control:%d MHz width:%d center: %d/%d MHz",
|
||||
chandef.chan->center_freq, chandef.width,
|
||||
chandef.center_freq1, chandef.center_freq2);
|
||||
"control:%d.%03d MHz width:%d center: %d.%03d/%d MHz",
|
||||
chandef.chan->center_freq, chandef.chan->freq_offset,
|
||||
chandef.width, chandef.center_freq1, chandef.freq1_offset,
|
||||
chandef.center_freq2);
|
||||
|
||||
if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef))
|
||||
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
|
||||
|
|
|
@ -994,6 +994,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
|||
/* stop the beacon */
|
||||
ifmsh->mesh_id_len = 0;
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
sdata->beacon_rate_set = false;
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
|
||||
|
||||
|
|
|
@ -162,6 +162,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
|||
chandef->chan = channel;
|
||||
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
|
||||
chandef->center_freq1 = channel->center_freq;
|
||||
chandef->freq1_offset = channel->freq_offset;
|
||||
|
||||
if (!ht_oper || !sta_ht_cap.ht_supported) {
|
||||
ret = IEEE80211_STA_DISABLE_HT |
|
||||
|
@ -396,9 +397,12 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
|
||||
sdata_info(sdata,
|
||||
"AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n",
|
||||
ifmgd->bssid, chandef.chan->center_freq, chandef.width,
|
||||
chandef.center_freq1, chandef.center_freq2);
|
||||
"AP %pM changed bandwidth, new config is %d.%03d MHz, "
|
||||
"width %d (%d.%03d/%d MHz)\n",
|
||||
ifmgd->bssid, chandef.chan->center_freq,
|
||||
chandef.chan->freq_offset, chandef.width,
|
||||
chandef.center_freq1, chandef.freq1_offset,
|
||||
chandef.center_freq2);
|
||||
|
||||
if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
|
||||
IEEE80211_STA_DISABLE_VHT |
|
||||
|
@ -1364,10 +1368,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
|
|||
if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
|
||||
IEEE80211_CHAN_DISABLED)) {
|
||||
sdata_info(sdata,
|
||||
"AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
|
||||
"AP %pM switches to unsupported channel "
|
||||
"(%d.%03d MHz, width:%d, CF1/2: %d.%03d/%d MHz), "
|
||||
"disconnecting\n",
|
||||
ifmgd->associated->bssid,
|
||||
csa_ie.chandef.chan->center_freq,
|
||||
csa_ie.chandef.chan->freq_offset,
|
||||
csa_ie.chandef.width, csa_ie.chandef.center_freq1,
|
||||
csa_ie.chandef.freq1_offset,
|
||||
csa_ie.chandef.center_freq2);
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&ifmgd->csa_connection_drop_work);
|
||||
|
@ -2948,10 +2956,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
|
||||
if (auth_alg == WLAN_AUTH_SAE &&
|
||||
status_code == WLAN_STATUS_ANTI_CLOG_REQUIRED)
|
||||
return;
|
||||
|
||||
sdata_info(sdata, "%pM denied authentication (status %d)\n",
|
||||
mgmt->sa, status_code);
|
||||
ieee80211_destroy_auth_data(sdata, false);
|
||||
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
|
||||
event.u.mlme.status = MLME_DENIED;
|
||||
event.u.mlme.reason = status_code;
|
||||
drv_event_callback(sdata->local, sdata, &event);
|
||||
|
@ -3149,15 +3162,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
|
|||
*have_higher_than_11mbit = true;
|
||||
|
||||
/*
|
||||
* Skip HT and VHT BSS membership selectors since they're not
|
||||
* rates.
|
||||
* Skip HT, VHT and HE BSS membership selectors since they're
|
||||
* not rates.
|
||||
*
|
||||
* Note: Even though the membership selector and the basic
|
||||
* rate flag share the same bit, they are not exactly
|
||||
* the same.
|
||||
*/
|
||||
if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
|
||||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY))
|
||||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) ||
|
||||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < sband->n_bitrates; j++) {
|
||||
|
@ -3249,7 +3263,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
return false;
|
||||
}
|
||||
|
||||
ifmgd->aid = aid;
|
||||
sdata->vif.bss_conf.aid = aid;
|
||||
ifmgd->tdls_chan_switch_prohibited =
|
||||
elems->ext_capab && elems->ext_capab_len >= 5 &&
|
||||
(elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);
|
||||
|
@ -3384,10 +3398,19 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
sta);
|
||||
|
||||
bss_conf->he_support = sta->sta.he_cap.has_he;
|
||||
if (elems->rsnx && elems->rsnx_len &&
|
||||
(elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) &&
|
||||
wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
NL80211_EXT_FEATURE_PROTECTED_TWT))
|
||||
bss_conf->twt_protected = true;
|
||||
else
|
||||
bss_conf->twt_protected = false;
|
||||
|
||||
changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
|
||||
} else {
|
||||
bss_conf->he_support = false;
|
||||
bss_conf->twt_requester = false;
|
||||
bss_conf->twt_protected = false;
|
||||
}
|
||||
|
||||
if (bss_conf->he_support) {
|
||||
|
@ -3521,9 +3544,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
|
|||
bss_conf->protected_keep_alive = false;
|
||||
}
|
||||
|
||||
/* set AID and assoc capability,
|
||||
/* set assoc capability (AID was already set earlier),
|
||||
* ieee80211_set_associated() will tell the driver */
|
||||
bss_conf->aid = aid;
|
||||
bss_conf->assoc_capability = capab_info;
|
||||
ieee80211_set_associated(sdata, cbss, changed);
|
||||
|
||||
|
@ -3661,7 +3683,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
|
||||
channel = ieee80211_get_channel_khz(local->hw.wiphy,
|
||||
ieee80211_rx_status_to_khz(rx_status));
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
|
@ -3877,7 +3900,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
return;
|
||||
}
|
||||
|
||||
if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
|
||||
if (ieee80211_rx_status_to_khz(rx_status) !=
|
||||
ieee80211_channel_to_khz(chanctx_conf->def.chan)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
@ -3948,7 +3972,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
mgmt->bssid, bssid);
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
|
||||
ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
|
||||
if (local->hw.conf.dynamic_ps_timeout > 0) {
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
||||
|
@ -5022,8 +5046,16 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
|
|||
* doesn't happen any more, but keep the workaround so
|
||||
* in case some *other* APs are buggy in different ways
|
||||
* we can connect -- with a warning.
|
||||
* Allow this workaround only in case the AP provided at least
|
||||
* one rate.
|
||||
*/
|
||||
if (!basic_rates && min_rate_index >= 0) {
|
||||
if (min_rate_index < 0) {
|
||||
sdata_info(sdata,
|
||||
"No legacy rates in association response\n");
|
||||
|
||||
sta_info_free(local, new_sta);
|
||||
return -EINVAL;
|
||||
} else if (!basic_rates) {
|
||||
sdata_info(sdata,
|
||||
"No basic rates, using min rate instead\n");
|
||||
basic_rates = BIT(min_rate_index);
|
||||
|
|
|
@ -557,6 +557,10 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
|
|||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
if (channel->freq_offset)
|
||||
/* this may work, but is untested */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (local->use_chanctx && !local->ops->remain_on_channel)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
|
||||
* Copyright (C) 2019-2020 Intel Corporation
|
||||
*/
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -490,7 +491,7 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
|
|||
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
|
||||
tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
|
||||
|
||||
if (tmp_cck_tp_rate && tmp_cck_tp > tmp_mcs_tp) {
|
||||
if (tmp_cck_tp > tmp_mcs_tp) {
|
||||
for(i = 0; i < MAX_THR_RATES; i++) {
|
||||
minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i],
|
||||
tmp_mcs_tp_rate);
|
||||
|
|
|
@ -412,6 +412,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
|
|||
pos++;
|
||||
|
||||
/* IEEE80211_RADIOTAP_CHANNEL */
|
||||
/* TODO: frequency offset in KHz */
|
||||
put_unaligned_le16(status->freq, pos);
|
||||
pos += 2;
|
||||
if (status->bw == RATE_INFO_BW_10)
|
||||
|
@ -1984,8 +1985,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
|
||||
if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
|
||||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
|
||||
NUM_DEFAULT_BEACON_KEYS)
|
||||
NUM_DEFAULT_BEACON_KEYS) {
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
skb->data,
|
||||
skb->len);
|
||||
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
|
||||
}
|
||||
|
||||
rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
|
||||
if (!rx->key)
|
||||
|
@ -2131,6 +2136,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
/* either the frame has been decrypted or will be dropped */
|
||||
status->flag |= RX_FLAG_DECRYPTED;
|
||||
|
||||
if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
skb->data, skb->len);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2411,8 +2420,12 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
|
|||
return -EACCES;
|
||||
}
|
||||
if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
|
||||
ieee80211_get_mmie_keyidx(rx->skb) < 0))
|
||||
ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
|
||||
cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
|
||||
rx->skb->data,
|
||||
rx->skb->len);
|
||||
return -EACCES;
|
||||
}
|
||||
/*
|
||||
* When using MFP, Action frames are not allowed prior to
|
||||
* having configured keys.
|
||||
|
|
|
@ -275,7 +275,8 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
|
||||
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
|
||||
channel = ieee80211_get_channel_khz(local->hw.wiphy,
|
||||
ieee80211_rx_status_to_khz(rx_status));
|
||||
|
||||
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
|
@ -896,6 +897,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
|
|||
|
||||
local->scan_chandef.chan = chan;
|
||||
local->scan_chandef.center_freq1 = chan->center_freq;
|
||||
local->scan_chandef.freq1_offset = chan->freq_offset;
|
||||
local->scan_chandef.center_freq2 = 0;
|
||||
switch (scan_req->scan_width) {
|
||||
case NL80211_BSS_CHAN_WIDTH_5:
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright 2002-2005, Devicescape Software, Inc.
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015-2017 Intel Deutschland GmbH
|
||||
* Copyright(c) 2020 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef STA_INFO_H
|
||||
|
@ -68,6 +69,8 @@
|
|||
* @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP.
|
||||
* @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX
|
||||
* until pending frames are delivered
|
||||
* @WLAN_STA_USES_ENCRYPTION: This station was configured for encryption,
|
||||
* so drop all packets without a key later.
|
||||
*
|
||||
* @NUM_WLAN_STA_FLAGS: number of defined flags
|
||||
*/
|
||||
|
@ -116,6 +119,7 @@ enum ieee80211_sta_info_flags {
|
|||
#define HT_AGG_STATE_WANT_STOP 5
|
||||
#define HT_AGG_STATE_START_CB 6
|
||||
#define HT_AGG_STATE_STOP_CB 7
|
||||
#define HT_AGG_STATE_SENT_ADDBA 8
|
||||
|
||||
DECLARE_EWMA(avg_signal, 10, 8)
|
||||
enum ieee80211_agg_stop_reason {
|
||||
|
|
|
@ -226,12 +226,11 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
|
|||
static void
|
||||
ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
u8 *pos = skb_put(skb, 4);
|
||||
|
||||
*pos++ = WLAN_EID_AID;
|
||||
*pos++ = 2; /* len */
|
||||
put_unaligned_le16(ifmgd->aid, pos);
|
||||
put_unaligned_le16(sdata->vif.bss_conf.aid, pos);
|
||||
}
|
||||
|
||||
/* translate numbering in the WMM parameter IE to the mac80211 notation */
|
||||
|
@ -1567,6 +1566,10 @@ ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
|||
u32 ch_sw_tm_ie;
|
||||
int ret;
|
||||
|
||||
if (chandef->chan->freq_offset)
|
||||
/* this may work, but is untested */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
sta = sta_info_get(sdata, addr);
|
||||
if (!sta) {
|
||||
|
|
|
@ -37,32 +37,42 @@
|
|||
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
|
||||
|
||||
#define CHANDEF_ENTRY __field(u32, control_freq) \
|
||||
__field(u32, freq_offset) \
|
||||
__field(u32, chan_width) \
|
||||
__field(u32, center_freq1) \
|
||||
__field(u32, freq1_offset) \
|
||||
__field(u32, center_freq2)
|
||||
#define CHANDEF_ASSIGN(c) \
|
||||
__entry->control_freq = (c) ? ((c)->chan ? (c)->chan->center_freq : 0) : 0; \
|
||||
__entry->freq_offset = (c) ? ((c)->chan ? (c)->chan->freq_offset : 0) : 0; \
|
||||
__entry->chan_width = (c) ? (c)->width : 0; \
|
||||
__entry->center_freq1 = (c) ? (c)->center_freq1 : 0; \
|
||||
__entry->freq1_offset = (c) ? (c)->freq1_offset : 0; \
|
||||
__entry->center_freq2 = (c) ? (c)->center_freq2 : 0;
|
||||
#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
|
||||
#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
|
||||
__entry->center_freq1, __entry->center_freq2
|
||||
#define CHANDEF_PR_FMT " control:%d.%03d MHz width:%d center: %d.%03d/%d MHz"
|
||||
#define CHANDEF_PR_ARG __entry->control_freq, __entry->freq_offset, __entry->chan_width, \
|
||||
__entry->center_freq1, __entry->freq1_offset, __entry->center_freq2
|
||||
|
||||
#define MIN_CHANDEF_ENTRY \
|
||||
__field(u32, min_control_freq) \
|
||||
__field(u32, min_freq_offset) \
|
||||
__field(u32, min_chan_width) \
|
||||
__field(u32, min_center_freq1) \
|
||||
__field(u32, min_freq1_offset) \
|
||||
__field(u32, min_center_freq2)
|
||||
|
||||
#define MIN_CHANDEF_ASSIGN(c) \
|
||||
__entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
|
||||
__entry->min_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0; \
|
||||
__entry->min_chan_width = (c)->width; \
|
||||
__entry->min_center_freq1 = (c)->center_freq1; \
|
||||
__entry->freq1_offset = (c)->freq1_offset; \
|
||||
__entry->min_center_freq2 = (c)->center_freq2;
|
||||
#define MIN_CHANDEF_PR_FMT " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
|
||||
#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_chan_width, \
|
||||
__entry->min_center_freq1, __entry->min_center_freq2
|
||||
#define MIN_CHANDEF_PR_FMT " min_control:%d.%03d MHz min_width:%d min_center: %d.%03d/%d MHz"
|
||||
#define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_freq_offset, \
|
||||
__entry->min_chan_width, \
|
||||
__entry->min_center_freq1, __entry->min_freq1_offset, \
|
||||
__entry->min_center_freq2
|
||||
|
||||
#define CHANCTX_ENTRY CHANDEF_ENTRY \
|
||||
MIN_CHANDEF_ENTRY \
|
||||
|
@ -412,6 +422,7 @@ TRACE_EVENT(drv_bss_info_changed,
|
|||
__field(s32, cqm_rssi_hyst)
|
||||
__field(u32, channel_width)
|
||||
__field(u32, channel_cfreq1)
|
||||
__field(u32, channel_cfreq1_offset)
|
||||
__dynamic_array(u32, arp_addr_list,
|
||||
info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
|
||||
IEEE80211_BSS_ARP_ADDR_LIST_LEN :
|
||||
|
@ -452,6 +463,7 @@ TRACE_EVENT(drv_bss_info_changed,
|
|||
__entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
|
||||
__entry->channel_width = info->chandef.width;
|
||||
__entry->channel_cfreq1 = info->chandef.center_freq1;
|
||||
__entry->channel_cfreq1_offset = info->chandef.freq1_offset;
|
||||
__entry->arp_addr_cnt = info->arp_addr_cnt;
|
||||
memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
|
||||
sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
|
||||
|
@ -1223,6 +1235,7 @@ TRACE_EVENT(drv_remain_on_channel,
|
|||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(int, center_freq)
|
||||
__field(int, freq_offset)
|
||||
__field(unsigned int, duration)
|
||||
__field(u32, type)
|
||||
),
|
||||
|
@ -1231,14 +1244,16 @@ TRACE_EVENT(drv_remain_on_channel,
|
|||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->center_freq = chan->center_freq;
|
||||
__entry->freq_offset = chan->freq_offset;
|
||||
__entry->duration = duration;
|
||||
__entry->type = type;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
|
||||
LOCAL_PR_FMT VIF_PR_FMT " freq:%d.%03dMHz duration:%dms type=%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG,
|
||||
__entry->center_freq, __entry->duration, __entry->type
|
||||
__entry->center_freq, __entry->freq_offset,
|
||||
__entry->duration, __entry->type
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1546,8 +1561,10 @@ struct trace_vif_entry {
|
|||
|
||||
struct trace_chandef_entry {
|
||||
u32 control_freq;
|
||||
u32 freq_offset;
|
||||
u32 chan_width;
|
||||
u32 center_freq1;
|
||||
u32 freq1_offset;
|
||||
u32 center_freq2;
|
||||
} __packed;
|
||||
|
||||
|
@ -1597,18 +1614,26 @@ TRACE_EVENT(drv_switch_vif_chanctx,
|
|||
sizeof(local_vifs[i].vif.vif_name));
|
||||
SWITCH_ENTRY_ASSIGN(old_chandef.control_freq,
|
||||
old_ctx->def.chan->center_freq);
|
||||
SWITCH_ENTRY_ASSIGN(old_chandef.freq_offset,
|
||||
old_ctx->def.chan->freq_offset);
|
||||
SWITCH_ENTRY_ASSIGN(old_chandef.chan_width,
|
||||
old_ctx->def.width);
|
||||
SWITCH_ENTRY_ASSIGN(old_chandef.center_freq1,
|
||||
old_ctx->def.center_freq1);
|
||||
SWITCH_ENTRY_ASSIGN(old_chandef.freq1_offset,
|
||||
old_ctx->def.freq1_offset);
|
||||
SWITCH_ENTRY_ASSIGN(old_chandef.center_freq2,
|
||||
old_ctx->def.center_freq2);
|
||||
SWITCH_ENTRY_ASSIGN(new_chandef.control_freq,
|
||||
new_ctx->def.chan->center_freq);
|
||||
SWITCH_ENTRY_ASSIGN(new_chandef.freq_offset,
|
||||
new_ctx->def.chan->freq_offset);
|
||||
SWITCH_ENTRY_ASSIGN(new_chandef.chan_width,
|
||||
new_ctx->def.width);
|
||||
SWITCH_ENTRY_ASSIGN(new_chandef.center_freq1,
|
||||
new_ctx->def.center_freq1);
|
||||
SWITCH_ENTRY_ASSIGN(new_chandef.freq1_offset,
|
||||
new_ctx->def.freq1_offset);
|
||||
SWITCH_ENTRY_ASSIGN(new_chandef.center_freq2,
|
||||
new_ctx->def.center_freq2);
|
||||
}
|
||||
|
|
|
@ -4883,6 +4883,9 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
txrc.bss_conf = &sdata->vif.bss_conf;
|
||||
txrc.skb = skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
|
||||
txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band];
|
||||
else
|
||||
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
|
||||
txrc.bss = true;
|
||||
rate_control_get_rate(sdata, NULL, &txrc);
|
||||
|
@ -5006,7 +5009,7 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
|
|||
pspoll = skb_put_zero(skb, sizeof(*pspoll));
|
||||
pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
|
||||
IEEE80211_STYPE_PSPOLL);
|
||||
pspoll->aid = cpu_to_le16(ifmgd->aid);
|
||||
pspoll->aid = cpu_to_le16(sdata->vif.bss_conf.aid);
|
||||
|
||||
/* aid in PS-Poll has its two MSBs each set to 1 */
|
||||
pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* Portions of this file
|
||||
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018 - 2019 Intel Corporation
|
||||
* Copyright (C) 2018 - 2020 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/ieee80211.h>
|
||||
|
@ -575,15 +575,21 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
|
||||
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
|
||||
/* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
|
||||
break;
|
||||
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ:
|
||||
/* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
|
||||
break;
|
||||
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ:
|
||||
if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80)
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
|
||||
else
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
|
||||
break;
|
||||
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
|
||||
/* legacy only, no longer used by newer spec */
|
||||
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
|
|||
return;
|
||||
|
||||
chandef->chan = chan;
|
||||
chandef->freq1_offset = chan->freq_offset;
|
||||
chandef->center_freq2 = 0;
|
||||
chandef->edmg.bw_config = 0;
|
||||
chandef->edmg.channels = 0;
|
||||
|
@ -146,6 +147,9 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
|||
if (!chandef->chan)
|
||||
return false;
|
||||
|
||||
if (chandef->freq1_offset >= 1000)
|
||||
return false;
|
||||
|
||||
control_freq = chandef->chan->center_freq;
|
||||
|
||||
switch (chandef->width) {
|
||||
|
@ -153,7 +157,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
|||
case NL80211_CHAN_WIDTH_10:
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
if (chandef->center_freq1 != control_freq)
|
||||
if (ieee80211_chandef_to_khz(chandef) !=
|
||||
ieee80211_channel_to_khz(chandef->chan))
|
||||
return false;
|
||||
if (chandef->center_freq2)
|
||||
return false;
|
||||
|
@ -386,10 +391,11 @@ static u32 cfg80211_get_start_freq(u32 center_freq,
|
|||
{
|
||||
u32 start_freq;
|
||||
|
||||
if (bandwidth <= 20)
|
||||
bandwidth = MHZ_TO_KHZ(bandwidth);
|
||||
if (bandwidth <= MHZ_TO_KHZ(20))
|
||||
start_freq = center_freq;
|
||||
else
|
||||
start_freq = center_freq - bandwidth/2 + 10;
|
||||
start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
|
||||
|
||||
return start_freq;
|
||||
}
|
||||
|
@ -399,10 +405,11 @@ static u32 cfg80211_get_end_freq(u32 center_freq,
|
|||
{
|
||||
u32 end_freq;
|
||||
|
||||
if (bandwidth <= 20)
|
||||
bandwidth = MHZ_TO_KHZ(bandwidth);
|
||||
if (bandwidth <= MHZ_TO_KHZ(20))
|
||||
end_freq = center_freq;
|
||||
else
|
||||
end_freq = center_freq + bandwidth/2 - 10;
|
||||
end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
|
||||
|
||||
return end_freq;
|
||||
}
|
||||
|
@ -417,8 +424,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
|
|||
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
|
||||
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
|
||||
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
|
||||
c = ieee80211_get_channel_khz(wiphy, freq);
|
||||
if (!c)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -449,7 +456,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
|
|||
return -EINVAL;
|
||||
|
||||
ret = cfg80211_get_chans_dfs_required(wiphy,
|
||||
chandef->center_freq1,
|
||||
ieee80211_chandef_to_khz(chandef),
|
||||
width);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -460,7 +467,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
|
|||
return 0;
|
||||
|
||||
ret = cfg80211_get_chans_dfs_required(wiphy,
|
||||
chandef->center_freq2,
|
||||
MHZ_TO_KHZ(chandef->center_freq2),
|
||||
width);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -503,8 +510,8 @@ static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
|
|||
* DFS_AVAILABLE). Return number of usable channels
|
||||
* (require CAC). Allow DFS and non-DFS channel mix.
|
||||
*/
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
|
||||
c = ieee80211_get_channel_khz(wiphy, freq);
|
||||
if (!c)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -536,7 +543,8 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
|
|||
if (width < 0)
|
||||
return false;
|
||||
|
||||
r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
|
||||
r1 = cfg80211_get_chans_dfs_usable(wiphy,
|
||||
MHZ_TO_KHZ(chandef->center_freq1),
|
||||
width);
|
||||
|
||||
if (r1 < 0)
|
||||
|
@ -546,7 +554,7 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
|
|||
case NL80211_CHAN_WIDTH_80P80:
|
||||
WARN_ON(!chandef->center_freq2);
|
||||
r2 = cfg80211_get_chans_dfs_usable(wiphy,
|
||||
chandef->center_freq2,
|
||||
MHZ_TO_KHZ(chandef->center_freq2),
|
||||
width);
|
||||
if (r2 < 0)
|
||||
return false;
|
||||
|
@ -694,8 +702,8 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
|
|||
* If any channel in between is disabled or has not
|
||||
* had gone through CAC return false
|
||||
*/
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
|
||||
c = ieee80211_get_channel_khz(wiphy, freq);
|
||||
if (!c)
|
||||
return false;
|
||||
|
||||
|
@ -724,7 +732,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
|
|||
if (width < 0)
|
||||
return false;
|
||||
|
||||
r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
|
||||
r = cfg80211_get_chans_dfs_available(wiphy,
|
||||
MHZ_TO_KHZ(chandef->center_freq1),
|
||||
width);
|
||||
|
||||
/* If any of channels unavailable for cf1 just return */
|
||||
|
@ -735,7 +744,7 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
|
|||
case NL80211_CHAN_WIDTH_80P80:
|
||||
WARN_ON(!chandef->center_freq2);
|
||||
r = cfg80211_get_chans_dfs_available(wiphy,
|
||||
chandef->center_freq2,
|
||||
MHZ_TO_KHZ(chandef->center_freq2),
|
||||
width);
|
||||
break;
|
||||
default:
|
||||
|
@ -757,8 +766,8 @@ static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
|
|||
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
|
||||
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
|
||||
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
|
||||
c = ieee80211_get_channel_khz(wiphy, freq);
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
|
@ -790,14 +799,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
|
|||
return 0;
|
||||
|
||||
t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
|
||||
chandef->center_freq1,
|
||||
MHZ_TO_KHZ(chandef->center_freq1),
|
||||
width);
|
||||
|
||||
if (!chandef->center_freq2)
|
||||
return t1;
|
||||
|
||||
t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
|
||||
chandef->center_freq2,
|
||||
MHZ_TO_KHZ(chandef->center_freq2),
|
||||
width);
|
||||
|
||||
return max(t1, t2);
|
||||
|
@ -813,8 +822,8 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
|
|||
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
|
||||
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
|
||||
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
|
||||
c = ieee80211_get_channel_khz(wiphy, freq);
|
||||
if (!c || c->flags & prohibited_flags)
|
||||
return false;
|
||||
}
|
||||
|
@ -976,13 +985,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
|||
prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
|
||||
|
||||
|
||||
if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
|
||||
if (!cfg80211_secondary_chans_ok(wiphy,
|
||||
ieee80211_chandef_to_khz(chandef),
|
||||
width, prohibited_flags))
|
||||
return false;
|
||||
|
||||
if (!chandef->center_freq2)
|
||||
return true;
|
||||
return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
|
||||
return cfg80211_secondary_chans_ok(wiphy,
|
||||
MHZ_TO_KHZ(chandef->center_freq2),
|
||||
width, prohibited_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_chandef_usable);
|
||||
|
|
|
@ -480,9 +480,6 @@ use_default_name:
|
|||
INIT_LIST_HEAD(&rdev->bss_list);
|
||||
INIT_LIST_HEAD(&rdev->sched_scan_req_list);
|
||||
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
|
||||
INIT_LIST_HEAD(&rdev->mlme_unreg);
|
||||
spin_lock_init(&rdev->mlme_unreg_lock);
|
||||
INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk);
|
||||
INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
|
||||
cfg80211_dfs_channels_update_work);
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
|
@ -837,6 +834,9 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
sband->channels[i].orig_mpwr =
|
||||
sband->channels[i].max_power;
|
||||
sband->channels[i].band = band;
|
||||
|
||||
if (WARN_ON(sband->channels[i].freq_offset >= 1000))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < sband->n_iftype_data; i++) {
|
||||
|
@ -1030,7 +1030,6 @@ void wiphy_unregister(struct wiphy *wiphy)
|
|||
cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
|
||||
flush_work(&rdev->destroy_work);
|
||||
flush_work(&rdev->sched_scan_stop_wk);
|
||||
flush_work(&rdev->mlme_unreg_wk);
|
||||
flush_work(&rdev->propagate_radar_detect_wk);
|
||||
flush_work(&rdev->propagate_cac_done_wk);
|
||||
|
||||
|
@ -1094,6 +1093,7 @@ static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync)
|
|||
rdev->devlist_generation++;
|
||||
|
||||
cfg80211_mlme_purge_registrations(wdev);
|
||||
flush_work(&wdev->mgmt_registrations_update_wk);
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
|
@ -1238,6 +1238,8 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev,
|
|||
spin_lock_init(&wdev->event_lock);
|
||||
INIT_LIST_HEAD(&wdev->mgmt_registrations);
|
||||
spin_lock_init(&wdev->mgmt_registrations_lock);
|
||||
INIT_WORK(&wdev->mgmt_registrations_update_wk,
|
||||
cfg80211_mgmt_registrations_update_wk);
|
||||
INIT_LIST_HEAD(&wdev->pmsr_list);
|
||||
spin_lock_init(&wdev->pmsr_lock);
|
||||
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
|
||||
|
|
|
@ -60,10 +60,6 @@ struct cfg80211_registered_device {
|
|||
struct list_head beacon_registrations;
|
||||
spinlock_t beacon_registrations_lock;
|
||||
|
||||
struct list_head mlme_unreg;
|
||||
spinlock_t mlme_unreg_lock;
|
||||
struct work_struct mlme_unreg_wk;
|
||||
|
||||
/* protected by RTNL only */
|
||||
int num_running_ifaces;
|
||||
int num_running_monitor_ifaces;
|
||||
|
@ -385,8 +381,9 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
|
|||
struct net_device *dev);
|
||||
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
|
||||
u16 frame_type, const u8 *match_data,
|
||||
int match_len, struct netlink_ext_ack *extack);
|
||||
void cfg80211_mlme_unreg_wk(struct work_struct *wk);
|
||||
int match_len, bool multicast_rx,
|
||||
struct netlink_ext_ack *extack);
|
||||
void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk);
|
||||
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
|
||||
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
|
||||
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
|
|
|
@ -426,58 +426,62 @@ struct cfg80211_mgmt_registration {
|
|||
|
||||
__le16 frame_type;
|
||||
|
||||
bool multicast_rx;
|
||||
|
||||
u8 match[];
|
||||
};
|
||||
|
||||
static void
|
||||
cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev)
|
||||
static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct wireless_dev *tmp;
|
||||
struct cfg80211_mgmt_registration *reg;
|
||||
struct mgmt_frame_regs upd = {};
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
spin_lock_bh(&rdev->mlme_unreg_lock);
|
||||
while ((reg = list_first_entry_or_null(&rdev->mlme_unreg,
|
||||
struct cfg80211_mgmt_registration,
|
||||
list))) {
|
||||
list_del(®->list);
|
||||
spin_unlock_bh(&rdev->mlme_unreg_lock);
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(tmp, &rdev->wiphy.wdev_list, list) {
|
||||
list_for_each_entry_rcu(reg, &tmp->mgmt_registrations, list) {
|
||||
u32 mask = BIT(le16_to_cpu(reg->frame_type) >> 4);
|
||||
u32 mcast_mask = 0;
|
||||
|
||||
if (rdev->ops->mgmt_frame_register) {
|
||||
u16 frame_type = le16_to_cpu(reg->frame_type);
|
||||
if (reg->multicast_rx)
|
||||
mcast_mask = mask;
|
||||
|
||||
rdev_mgmt_frame_register(rdev, reg->wdev,
|
||||
frame_type, false);
|
||||
upd.global_stypes |= mask;
|
||||
upd.global_mcast_stypes |= mcast_mask;
|
||||
|
||||
if (tmp == wdev) {
|
||||
upd.interface_stypes |= mask;
|
||||
upd.interface_mcast_stypes |= mcast_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
rdev_update_mgmt_frame_registrations(rdev, wdev, &upd);
|
||||
}
|
||||
|
||||
kfree(reg);
|
||||
|
||||
spin_lock_bh(&rdev->mlme_unreg_lock);
|
||||
}
|
||||
spin_unlock_bh(&rdev->mlme_unreg_lock);
|
||||
}
|
||||
|
||||
void cfg80211_mlme_unreg_wk(struct work_struct *wk)
|
||||
void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
rdev = container_of(wk, struct cfg80211_registered_device,
|
||||
mlme_unreg_wk);
|
||||
struct wireless_dev *wdev = container_of(wk, struct wireless_dev,
|
||||
mgmt_registrations_update_wk);
|
||||
|
||||
rtnl_lock();
|
||||
cfg80211_process_mlme_unregistrations(rdev);
|
||||
cfg80211_mgmt_registrations_update(wdev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
|
||||
u16 frame_type, const u8 *match_data,
|
||||
int match_len, struct netlink_ext_ack *extack)
|
||||
int match_len, bool multicast_rx,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_mgmt_registration *reg, *nreg;
|
||||
int err = 0;
|
||||
u16 mgmt_type;
|
||||
bool update_multicast = false;
|
||||
|
||||
if (!wdev->wiphy->mgmt_stypes)
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -528,34 +532,39 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
|
|||
continue;
|
||||
|
||||
if (memcmp(reg->match, match_data, mlen) == 0) {
|
||||
if (reg->multicast_rx != multicast_rx) {
|
||||
update_multicast = true;
|
||||
reg->multicast_rx = multicast_rx;
|
||||
break;
|
||||
}
|
||||
NL_SET_ERR_MSG(extack, "Match already configured");
|
||||
err = -EALREADY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
kfree(nreg);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (update_multicast) {
|
||||
kfree(nreg);
|
||||
} else {
|
||||
memcpy(nreg->match, match_data, match_len);
|
||||
nreg->match_len = match_len;
|
||||
nreg->nlportid = snd_portid;
|
||||
nreg->frame_type = cpu_to_le16(frame_type);
|
||||
nreg->wdev = wdev;
|
||||
nreg->multicast_rx = multicast_rx;
|
||||
list_add(&nreg->list, &wdev->mgmt_registrations);
|
||||
}
|
||||
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
||||
|
||||
/* process all unregistrations to avoid driver confusion */
|
||||
cfg80211_process_mlme_unregistrations(rdev);
|
||||
|
||||
if (rdev->ops->mgmt_frame_register)
|
||||
rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
|
||||
cfg80211_mgmt_registrations_update(wdev);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
kfree(nreg);
|
||||
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
||||
|
||||
return err;
|
||||
|
@ -574,11 +583,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
|
|||
continue;
|
||||
|
||||
list_del(®->list);
|
||||
spin_lock(&rdev->mlme_unreg_lock);
|
||||
list_add_tail(®->list, &rdev->mlme_unreg);
|
||||
spin_unlock(&rdev->mlme_unreg_lock);
|
||||
kfree(reg);
|
||||
|
||||
schedule_work(&rdev->mlme_unreg_wk);
|
||||
schedule_work(&wdev->mgmt_registrations_update_wk);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
||||
|
@ -594,15 +601,16 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
|
|||
|
||||
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_mgmt_registration *reg, *tmp;
|
||||
|
||||
spin_lock_bh(&wdev->mgmt_registrations_lock);
|
||||
spin_lock(&rdev->mlme_unreg_lock);
|
||||
list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg);
|
||||
spin_unlock(&rdev->mlme_unreg_lock);
|
||||
list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
|
||||
list_del(®->list);
|
||||
kfree(reg);
|
||||
}
|
||||
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
||||
|
||||
cfg80211_process_mlme_unregistrations(rdev);
|
||||
cfg80211_mgmt_registrations_update(wdev);
|
||||
}
|
||||
|
||||
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
|
|
|
@ -635,6 +635,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
[NL80211_ATTR_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
|
||||
[NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
|
||||
[NL80211_ATTR_RECEIVE_MULTICAST] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -3860,15 +3861,26 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
|
|||
};
|
||||
void *hdr;
|
||||
struct sk_buff *msg;
|
||||
bool bigtk_support = false;
|
||||
|
||||
if (wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_BEACON_PROTECTION))
|
||||
bigtk_support = true;
|
||||
|
||||
if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
|
||||
dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
|
||||
wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
|
||||
bigtk_support = true;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_KEY_IDX]) {
|
||||
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
|
||||
if (key_idx > 5 &&
|
||||
!wiphy_ext_feature_isset(
|
||||
&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_BEACON_PROTECTION))
|
||||
|
||||
if (key_idx >= 6 && key_idx <= 7 && !bigtk_support) {
|
||||
GENL_SET_ERR_MSG(info, "BIGTK not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC])
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
@ -4679,6 +4691,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
|
|||
params->ht_required = true;
|
||||
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
|
||||
params->vht_required = true;
|
||||
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
|
||||
params->he_required = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10726,9 +10740,18 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!rdev->ops->mgmt_tx)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_RECEIVE_MULTICAST] &&
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS)) {
|
||||
GENL_SET_ERR_MSG(info,
|
||||
"multicast RX registrations are not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
|
||||
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
|
||||
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
|
||||
info->attrs[NL80211_ATTR_RECEIVE_MULTICAST],
|
||||
info->extack);
|
||||
}
|
||||
|
||||
|
@ -15495,10 +15518,19 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
|
|||
if (WARN_ON(len < 2))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_deauth(mgmt->frame_control))
|
||||
if (ieee80211_is_deauth(mgmt->frame_control)) {
|
||||
cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
|
||||
else
|
||||
} else if (ieee80211_is_disassoc(mgmt->frame_control)) {
|
||||
cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
|
||||
} else if (ieee80211_is_beacon(mgmt->frame_control)) {
|
||||
if (wdev->unprot_beacon_reported &&
|
||||
elapsed_jiffies_msecs(wdev->unprot_beacon_reported) < 10000)
|
||||
return;
|
||||
cmd = NL80211_CMD_UNPROT_BEACON;
|
||||
wdev->unprot_beacon_reported = jiffies;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
|
||||
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
|
||||
|
|
|
@ -819,13 +819,16 @@ rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
static inline void
|
||||
rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, u16 frame_type, bool reg)
|
||||
rdev_update_mgmt_frame_registrations(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct mgmt_frame_regs *upd)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
|
||||
rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
|
||||
trace_rdev_update_mgmt_frame_registrations(&rdev->wiphy, wdev, upd);
|
||||
if (rdev->ops->update_mgmt_frame_registrations)
|
||||
rdev->ops->update_mgmt_frame_registrations(&rdev->wiphy, wdev,
|
||||
upd);
|
||||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
|
|
|
@ -1658,22 +1658,23 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
|
|||
const struct ieee80211_channel *chan)
|
||||
{
|
||||
const struct ieee80211_freq_range *freq_range = NULL;
|
||||
u32 max_bandwidth_khz, bw_flags = 0;
|
||||
u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
|
||||
|
||||
freq_range = ®_rule->freq_range;
|
||||
|
||||
max_bandwidth_khz = freq_range->max_bandwidth_khz;
|
||||
center_freq_khz = ieee80211_channel_to_khz(chan);
|
||||
/* Check if auto calculation requested */
|
||||
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
|
||||
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
|
||||
|
||||
/* If we get a reg_rule we can assume that at least 5Mhz fit */
|
||||
if (!cfg80211_does_bw_fit_range(freq_range,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
center_freq_khz,
|
||||
MHZ_TO_KHZ(10)))
|
||||
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
|
||||
if (!cfg80211_does_bw_fit_range(freq_range,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
center_freq_khz,
|
||||
MHZ_TO_KHZ(20)))
|
||||
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
|
||||
|
||||
|
@ -1710,7 +1711,7 @@ static void handle_channel(struct wiphy *wiphy,
|
|||
|
||||
flags = chan->orig_flags;
|
||||
|
||||
reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
|
||||
reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan));
|
||||
if (IS_ERR(reg_rule)) {
|
||||
/*
|
||||
* We will disable all channels that do not match our
|
||||
|
@ -1729,13 +1730,13 @@ static void handle_channel(struct wiphy *wiphy,
|
|||
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||
request_wiphy && request_wiphy == wiphy &&
|
||||
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
|
||||
pr_debug("Disabling freq %d MHz for good\n",
|
||||
chan->center_freq);
|
||||
pr_debug("Disabling freq %d.%03d MHz for good\n",
|
||||
chan->center_freq, chan->freq_offset);
|
||||
chan->orig_flags |= IEEE80211_CHAN_DISABLED;
|
||||
chan->flags = chan->orig_flags;
|
||||
} else {
|
||||
pr_debug("Disabling freq %d MHz\n",
|
||||
chan->center_freq);
|
||||
pr_debug("Disabling freq %d.%03d MHz\n",
|
||||
chan->center_freq, chan->freq_offset);
|
||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||
}
|
||||
return;
|
||||
|
@ -1936,7 +1937,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
|
|||
sband = wiphy->bands[reg_beacon->chan.band];
|
||||
chan = &sband->channels[chan_idx];
|
||||
|
||||
if (likely(chan->center_freq != reg_beacon->chan.center_freq))
|
||||
if (likely(!ieee80211_channel_equal(chan, ®_beacon->chan)))
|
||||
return;
|
||||
|
||||
if (chan->beacon_found)
|
||||
|
@ -2269,18 +2270,18 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
|||
u32 bw_flags = 0;
|
||||
const struct ieee80211_reg_rule *reg_rule = NULL;
|
||||
const struct ieee80211_power_rule *power_rule = NULL;
|
||||
u32 bw;
|
||||
u32 bw, center_freq_khz;
|
||||
|
||||
center_freq_khz = ieee80211_channel_to_khz(chan);
|
||||
for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
|
||||
reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq),
|
||||
regd, bw);
|
||||
reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw);
|
||||
if (!IS_ERR(reg_rule))
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(reg_rule)) {
|
||||
pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
|
||||
chan->center_freq);
|
||||
pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n",
|
||||
chan->center_freq, chan->freq_offset);
|
||||
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
|
||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||
} else {
|
||||
|
@ -3337,8 +3338,8 @@ static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
|
|||
struct reg_beacon *pending_beacon;
|
||||
|
||||
list_for_each_entry(pending_beacon, ®_pending_beacons, list)
|
||||
if (beacon_chan->center_freq ==
|
||||
pending_beacon->chan.center_freq)
|
||||
if (ieee80211_channel_equal(beacon_chan,
|
||||
&pending_beacon->chan))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -3367,9 +3368,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
|
|||
if (!reg_beacon)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
|
||||
beacon_chan->center_freq,
|
||||
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
||||
pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n",
|
||||
beacon_chan->center_freq, beacon_chan->freq_offset,
|
||||
ieee80211_freq_khz_to_channel(
|
||||
ieee80211_channel_to_khz(beacon_chan)),
|
||||
wiphy_name(wiphy));
|
||||
|
||||
memcpy(®_beacon->chan, beacon_chan,
|
||||
|
|
|
@ -1322,8 +1322,8 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
|||
return channel;
|
||||
}
|
||||
|
||||
freq = ieee80211_channel_to_frequency(channel_number, channel->band);
|
||||
alt_channel = ieee80211_get_channel(wiphy, freq);
|
||||
freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
|
||||
alt_channel = ieee80211_get_channel_khz(wiphy, freq);
|
||||
if (!alt_channel) {
|
||||
if (channel->band == NL80211_BAND_2GHZ) {
|
||||
/*
|
||||
|
|
|
@ -694,6 +694,7 @@ void __cfg80211_connect_result(struct net_device *dev,
|
|||
return;
|
||||
}
|
||||
|
||||
wdev->unprot_beacon_reported = 0;
|
||||
nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
|
||||
GFP_KERNEL);
|
||||
|
||||
|
@ -921,6 +922,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
|
|||
cfg80211_hold_bss(bss_from_pub(info->bss));
|
||||
wdev->current_bss = bss_from_pub(info->bss);
|
||||
|
||||
wdev->unprot_beacon_reported = 0;
|
||||
nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
|
||||
wdev->netdev, info, GFP_KERNEL);
|
||||
|
||||
|
|
|
@ -112,24 +112,29 @@
|
|||
} while (0)
|
||||
|
||||
#define CHAN_ENTRY __field(enum nl80211_band, band) \
|
||||
__field(u32, center_freq)
|
||||
__field(u32, center_freq) \
|
||||
__field(u16, freq_offset)
|
||||
#define CHAN_ASSIGN(chan) \
|
||||
do { \
|
||||
if (chan) { \
|
||||
__entry->band = chan->band; \
|
||||
__entry->center_freq = chan->center_freq; \
|
||||
__entry->freq_offset = chan->freq_offset; \
|
||||
} else { \
|
||||
__entry->band = 0; \
|
||||
__entry->center_freq = 0; \
|
||||
__entry->freq_offset = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define CHAN_PR_FMT "band: %d, freq: %u"
|
||||
#define CHAN_PR_ARG __entry->band, __entry->center_freq
|
||||
#define CHAN_PR_FMT "band: %d, freq: %u.%03u"
|
||||
#define CHAN_PR_ARG __entry->band, __entry->center_freq, __entry->freq_offset
|
||||
|
||||
#define CHAN_DEF_ENTRY __field(enum nl80211_band, band) \
|
||||
__field(u32, control_freq) \
|
||||
__field(u32, freq_offset) \
|
||||
__field(u32, width) \
|
||||
__field(u32, center_freq1) \
|
||||
__field(u32, freq1_offset) \
|
||||
__field(u32, center_freq2)
|
||||
#define CHAN_DEF_ASSIGN(chandef) \
|
||||
do { \
|
||||
|
@ -137,21 +142,27 @@
|
|||
__entry->band = (chandef)->chan->band; \
|
||||
__entry->control_freq = \
|
||||
(chandef)->chan->center_freq; \
|
||||
__entry->freq_offset = \
|
||||
(chandef)->chan->freq_offset; \
|
||||
__entry->width = (chandef)->width; \
|
||||
__entry->center_freq1 = (chandef)->center_freq1;\
|
||||
__entry->freq1_offset = (chandef)->freq1_offset;\
|
||||
__entry->center_freq2 = (chandef)->center_freq2;\
|
||||
} else { \
|
||||
__entry->band = 0; \
|
||||
__entry->control_freq = 0; \
|
||||
__entry->freq_offset = 0; \
|
||||
__entry->width = 0; \
|
||||
__entry->center_freq1 = 0; \
|
||||
__entry->freq1_offset = 0; \
|
||||
__entry->center_freq2 = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define CHAN_DEF_PR_FMT \
|
||||
"band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
|
||||
"band: %d, control freq: %u.%03u, width: %d, cf1: %u.%03u, cf2: %u"
|
||||
#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \
|
||||
__entry->width, __entry->center_freq1, \
|
||||
__entry->freq_offset, __entry->width, \
|
||||
__entry->center_freq1, __entry->freq1_offset, \
|
||||
__entry->center_freq2
|
||||
|
||||
#define SINFO_ENTRY __field(int, generation) \
|
||||
|
@ -1582,25 +1593,25 @@ TRACE_EVENT(rdev_set_bitrate_mask,
|
|||
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_mgmt_frame_register,
|
||||
TRACE_EVENT(rdev_update_mgmt_frame_registrations,
|
||||
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg),
|
||||
TP_ARGS(wiphy, wdev, frame_type, reg),
|
||||
struct mgmt_frame_regs *upd),
|
||||
TP_ARGS(wiphy, wdev, upd),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
WDEV_ENTRY
|
||||
__field(u16, frame_type)
|
||||
__field(bool, reg)
|
||||
__field(u16, global_stypes)
|
||||
__field(u16, interface_stypes)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WDEV_ASSIGN;
|
||||
__entry->frame_type = frame_type;
|
||||
__entry->reg = reg;
|
||||
__entry->global_stypes = upd->global_stypes;
|
||||
__entry->interface_stypes = upd->interface_stypes;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type,
|
||||
__entry->reg ? "true" : "false")
|
||||
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", global: 0x%.2x, intf: 0x%.2x",
|
||||
WIPHY_PR_ARG, WDEV_PR_ARG,
|
||||
__entry->global_stypes, __entry->interface_stypes)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_return_int_tx_rx,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/bitops.h>
|
||||
|
@ -72,7 +72,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
|
|||
}
|
||||
EXPORT_SYMBOL(ieee80211_mandatory_rates);
|
||||
|
||||
int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
|
||||
u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
|
||||
{
|
||||
/* see 802.11 17.3.8.3.2 and Annex J
|
||||
* there are overlapping channel numbers in 5GHz and 2GHz bands */
|
||||
|
@ -81,15 +81,15 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
|
|||
switch (band) {
|
||||
case NL80211_BAND_2GHZ:
|
||||
if (chan == 14)
|
||||
return 2484;
|
||||
return MHZ_TO_KHZ(2484);
|
||||
else if (chan < 14)
|
||||
return 2407 + chan * 5;
|
||||
return MHZ_TO_KHZ(2407 + chan * 5);
|
||||
break;
|
||||
case NL80211_BAND_5GHZ:
|
||||
if (chan >= 182 && chan <= 196)
|
||||
return 4000 + chan * 5;
|
||||
return MHZ_TO_KHZ(4000 + chan * 5);
|
||||
else
|
||||
return 5000 + chan * 5;
|
||||
return MHZ_TO_KHZ(5000 + chan * 5);
|
||||
break;
|
||||
case NL80211_BAND_6GHZ:
|
||||
/* see 802.11ax D4.1 27.3.22.2 */
|
||||
|
@ -98,17 +98,20 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
|
|||
break;
|
||||
case NL80211_BAND_60GHZ:
|
||||
if (chan < 7)
|
||||
return 56160 + chan * 2160;
|
||||
return MHZ_TO_KHZ(56160 + chan * 2160);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return 0; /* not supported */
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
|
||||
EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
|
||||
|
||||
int ieee80211_frequency_to_channel(int freq)
|
||||
int ieee80211_freq_khz_to_channel(u32 freq)
|
||||
{
|
||||
/* TODO: just handle MHz for now */
|
||||
freq = KHZ_TO_MHZ(freq);
|
||||
|
||||
/* see 802.11 17.3.8.3.2 and Annex J */
|
||||
if (freq == 2484)
|
||||
return 14;
|
||||
|
@ -126,9 +129,10 @@ int ieee80211_frequency_to_channel(int freq)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
|
||||
EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
|
||||
|
||||
struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
|
||||
struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
|
||||
u32 freq)
|
||||
{
|
||||
enum nl80211_band band;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
@ -141,14 +145,16 @@ struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
|
|||
continue;
|
||||
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
if (sband->channels[i].center_freq == freq)
|
||||
return &sband->channels[i];
|
||||
struct ieee80211_channel *chan = &sband->channels[i];
|
||||
|
||||
if (ieee80211_channel_to_khz(chan) == freq)
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_channel);
|
||||
EXPORT_SYMBOL(ieee80211_get_channel_khz);
|
||||
|
||||
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
|
||||
{
|
||||
|
@ -2030,10 +2036,10 @@ EXPORT_SYMBOL(cfg80211_send_layer2_update);
|
|||
|
||||
int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
||||
enum ieee80211_vht_chanwidth bw,
|
||||
int mcs, bool ext_nss_bw_capable)
|
||||
int mcs, bool ext_nss_bw_capable,
|
||||
unsigned int max_vht_nss)
|
||||
{
|
||||
u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map);
|
||||
int max_vht_nss = 0;
|
||||
int ext_nss_bw;
|
||||
int supp_width;
|
||||
int i, mcs_encoding;
|
||||
|
@ -2041,7 +2047,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
if (map == 0xffff)
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(mcs > 9))
|
||||
if (WARN_ON(mcs > 9 || max_vht_nss > 8))
|
||||
return 0;
|
||||
if (mcs <= 7)
|
||||
mcs_encoding = 0;
|
||||
|
@ -2050,6 +2056,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
else
|
||||
mcs_encoding = 2;
|
||||
|
||||
if (!max_vht_nss) {
|
||||
/* find max_vht_nss for the given MCS */
|
||||
for (i = 7; i >= 0; i--) {
|
||||
int supp = (map >> (2 * i)) & 3;
|
||||
|
@ -2062,6 +2069,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cap->supp_mcs.tx_mcs_map &
|
||||
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))
|
||||
|
|
Loading…
Reference in New Issue