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:
David S. Miller
2020-05-26 20:17:35 -07:00
49 changed files with 900 additions and 469 deletions

View File

@@ -1178,8 +1178,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
sizeof(arg->peer_he_cap_macinfo)); sizeof(arg->peer_he_cap_macinfo));
memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info, memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
sizeof(arg->peer_he_cap_phyinfo)); sizeof(arg->peer_he_cap_phyinfo));
memcpy(&arg->peer_he_ops, &vif->bss_conf.he_operation, arg->peer_he_ops = vif->bss_conf.he_oper.params;
sizeof(arg->peer_he_ops));
/* the top most byte is used to indicate BSS color info */ /* the top most byte is used to indicate BSS color info */
arg->peer_he_ops &= 0xffffff; arg->peer_he_ops &= 0xffffff;

View File

@@ -3249,22 +3249,19 @@ static int ath6kl_get_antenna(struct wiphy *wiphy,
return 0; 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, struct wireless_dev *wdev,
u16 frame_type, bool reg) struct mgmt_frame_regs *upd)
{ {
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); 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 * FIXME: send WMI_PROBE_REQ_REPORT_CMD here instead of hardcoding
* we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we * the reporting in the target all the time, this callback
* hardcode target to report Probe Request frames all the time. * *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, 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, .remain_on_channel = ath6kl_remain_on_channel,
.cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
.mgmt_tx = ath6kl_mgmt_tx, .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, .get_antenna = ath6kl_get_antenna,
.sched_scan_start = ath6kl_cfg80211_sscan_start, .sched_scan_start = ath6kl_cfg80211_sscan_start,
.sched_scan_stop = ath6kl_cfg80211_sscan_stop, .sched_scan_stop = ath6kl_cfg80211_sscan_stop,

View File

@@ -5031,21 +5031,15 @@ brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
} }
static void static void
brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
u16 frame_type, bool reg) struct mgmt_frame_regs *upd)
{ {
struct brcmf_cfg80211_vif *vif; 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); vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
if (reg)
vif->mgmt_rx_reg |= BIT(mgmt_type); vif->mgmt_rx_reg = upd->interface_stypes;
else
vif->mgmt_rx_reg &= ~BIT(mgmt_type);
} }
@@ -5460,7 +5454,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.change_station = brcmf_cfg80211_change_station, .change_station = brcmf_cfg80211_change_station,
.sched_scan_start = brcmf_cfg80211_sched_scan_start, .sched_scan_start = brcmf_cfg80211_sched_scan_start,
.sched_scan_stop = brcmf_cfg80211_sched_scan_stop, .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, .mgmt_tx = brcmf_cfg80211_mgmt_tx,
.remain_on_channel = brcmf_p2p_remain_on_channel, .remain_on_channel = brcmf_p2p_remain_on_channel,
.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,

View File

@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only // 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) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* Copyright(c) 2018 - 2019 Intel Corporation
* *
* Contact Information: * Contact Information:
* Intel Linux Wireless <linuxwifi@intel.com> * 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, if (ieee80211_get_vht_max_nss(&vht_cap,
IEEE80211_VHT_CHANWIDTH_160MHZ, 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_80;
return RATE_MCS_CHAN_WIDTH_160; return RATE_MCS_CHAN_WIDTH_160;
case IEEE80211_STA_RX_BW_80: case IEEE80211_STA_RX_BW_80:

View File

@@ -1068,6 +1068,47 @@ static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
return res; 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) static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate)
{ {
u16 result = 0; u16 result = 0;
@@ -1545,6 +1586,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
vif->addr); vif->addr);
hwsim_set_magic(vif); hwsim_set_magic(vif);
if (vif->type != NL80211_IFTYPE_MONITOR)
mac80211_hwsim_config_mac_nl(hw, vif->addr, true);
vif->cab_queue = 0; vif->cab_queue = 0;
vif->hw_queue[IEEE80211_AC_VO] = 0; vif->hw_queue[IEEE80211_AC_VO] = 0;
vif->hw_queue[IEEE80211_AC_VI] = 1; vif->hw_queue[IEEE80211_AC_VI] = 1;
@@ -1584,6 +1628,8 @@ static void mac80211_hwsim_remove_interface(
vif->addr); vif->addr);
hwsim_check_magic(vif); hwsim_check_magic(vif);
hwsim_clear_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, 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; data->rx_filter = 0;
if (*total_flags & FIF_ALLMULTI) if (*total_flags & FIF_ALLMULTI)
data->rx_filter |= FIF_ALLMULTI; data->rx_filter |= FIF_ALLMULTI;
if (*total_flags & FIF_MCAST_ACTION)
data->rx_filter |= FIF_MCAST_ACTION;
*total_flags = data->rx_filter; *total_flags = data->rx_filter;
} }
@@ -2104,6 +2152,8 @@ static void hw_scan_work(struct work_struct *work)
hwsim->hw_scan_vif = NULL; hwsim->hw_scan_vif = NULL;
hwsim->tmp_chan = NULL; hwsim->tmp_chan = NULL;
mutex_unlock(&hwsim->mutex); mutex_unlock(&hwsim->mutex);
mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr,
false);
return; return;
} }
@@ -2177,6 +2227,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
mutex_unlock(&hwsim->mutex); mutex_unlock(&hwsim->mutex);
mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true);
wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n"); wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n");
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); 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"); pr_debug("hwsim sw_scan request, prepping stuff\n");
memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN);
mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true);
hwsim->scanning = true; hwsim->scanning = true;
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); 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"); pr_debug("hwsim sw_scan_complete\n");
hwsim->scanning = false; hwsim->scanning = false;
mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false);
eth_zero_addr(hwsim->scan_addr); eth_zero_addr(hwsim->scan_addr);
mutex_unlock(&hwsim->mutex); 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); WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
} }
static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
{
return 1;
}
#define HWSIM_COMMON_OPS \ #define HWSIM_COMMON_OPS \
.tx = mac80211_hwsim_tx, \ .tx = mac80211_hwsim_tx, \
.start = mac80211_hwsim_start, \ .start = mac80211_hwsim_start, \
@@ -2423,6 +2481,7 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
.config = mac80211_hwsim_config, \ .config = mac80211_hwsim_config, \
.configure_filter = mac80211_hwsim_configure_filter, \ .configure_filter = mac80211_hwsim_configure_filter, \
.bss_info_changed = mac80211_hwsim_bss_info_changed, \ .bss_info_changed = mac80211_hwsim_bss_info_changed, \
.tx_last_beacon = mac80211_hwsim_tx_last_beacon, \
.sta_add = mac80211_hwsim_sta_add, \ .sta_add = mac80211_hwsim_sta_add, \
.sta_remove = mac80211_hwsim_sta_remove, \ .sta_remove = mac80211_hwsim_sta_remove, \
.sta_notify = mac80211_hwsim_sta_notify, \ .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; 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_VHT_IBSS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); 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; hw->wiphy->interface_modes = param->iftypes;

View File

@@ -75,6 +75,12 @@ enum hwsim_tx_control_flags {
* @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
* @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses: * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
* %HWSIM_ATTR_RADIO_ID * %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 * @__HWSIM_CMD_MAX: enum limit
*/ */
enum { enum {
@@ -85,6 +91,8 @@ enum {
HWSIM_CMD_NEW_RADIO, HWSIM_CMD_NEW_RADIO,
HWSIM_CMD_DEL_RADIO, HWSIM_CMD_DEL_RADIO,
HWSIM_CMD_GET_RADIO, HWSIM_CMD_GET_RADIO,
HWSIM_CMD_ADD_MAC_ADDR,
HWSIM_CMD_DEL_MAC_ADDR,
__HWSIM_CMD_MAX, __HWSIM_CMD_MAX,
}; };
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)

View File

@@ -269,17 +269,12 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
* CFG802.11 operation handler to register a mgmt frame. * CFG802.11 operation handler to register a mgmt frame.
*/ */
static void static void
mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy, mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
u16 frame_type, bool reg) struct mgmt_frame_regs *upd)
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
u32 mask; u32 mask = upd->interface_stypes;
if (reg)
mask = priv->mgmt_frame_mask | BIT(frame_type >> 4);
else
mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4);
if (mask != priv->mgmt_frame_mask) { if (mask != priv->mgmt_frame_mask) {
priv->mgmt_frame_mask = mask; priv->mgmt_frame_mask = mask;
@@ -4187,7 +4182,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.del_key = mwifiex_cfg80211_del_key, .del_key = mwifiex_cfg80211_del_key,
.set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key, .set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key,
.mgmt_tx = mwifiex_cfg80211_mgmt_tx, .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, .remain_on_channel = mwifiex_cfg80211_remain_on_channel,
.cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel, .cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel,
.set_default_key = mwifiex_cfg80211_set_default_key, .set_default_key = mwifiex_cfg80211_set_default_key,

View File

@@ -389,55 +389,57 @@ static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed)
} }
static void static void
qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, qtnf_update_mgmt_frame_registrations(struct wiphy *wiphy,
u16 frame_type, bool reg) struct wireless_dev *wdev,
struct mgmt_frame_regs *upd)
{ {
struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
u16 mgmt_type; u16 new_mask = upd->interface_stypes;
u16 new_mask; u16 old_mask = vif->mgmt_frames_bitmask;
u16 qlink_frame_type = 0; static const struct {
u16 mask, qlink_type;
} updates[] = {
{
.mask = BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
BIT(IEEE80211_STYPE_ASSOC_REQ >> 4),
.qlink_type = QLINK_MGMT_FRAME_ASSOC_REQ,
},
{
.mask = BIT(IEEE80211_STYPE_AUTH >> 4),
.qlink_type = QLINK_MGMT_FRAME_AUTH,
},
{
.mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
.qlink_type = QLINK_MGMT_FRAME_PROBE_REQ,
},
{
.mask = BIT(IEEE80211_STYPE_ACTION >> 4),
.qlink_type = QLINK_MGMT_FRAME_ACTION,
},
};
unsigned int i;
mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; if (new_mask == old_mask)
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)
return; return;
switch (frame_type & IEEE80211_FCTL_STYPE) { for (i = 0; i < ARRAY_SIZE(updates); i++) {
case IEEE80211_STYPE_REASSOC_REQ: u16 mask = updates[i].mask;
case IEEE80211_STYPE_ASSOC_REQ: u16 qlink_frame_type = updates[i].qlink_type;
qlink_frame_type = QLINK_MGMT_FRAME_ASSOC_REQ; bool reg;
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;
}
if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) { /* the ! are here due to the assoc/reassoc merge */
pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n", 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", vif->mac->macid, vif->vifid, reg ? "" : "un",
frame_type); qlink_frame_type);
return;
} }
vif->mgmt_frames_bitmask = new_mask; 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 static int
@@ -1017,7 +1019,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
.change_beacon = qtnf_change_beacon, .change_beacon = qtnf_change_beacon,
.stop_ap = qtnf_stop_ap, .stop_ap = qtnf_stop_ap,
.set_wiphy_params = qtnf_set_wiphy_params, .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, .mgmt_tx = qtnf_mgmt_tx,
.change_station = qtnf_change_station, .change_station = qtnf_change_station,
.del_station = qtnf_del_station, .del_station = qtnf_del_station,

View File

@@ -3163,29 +3163,6 @@ exit:
return ret; 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) #if defined(CONFIG_PNO_SUPPORT)
static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
@@ -3397,7 +3374,6 @@ static struct cfg80211_ops rtw_cfg80211_ops = {
.change_bss = cfg80211_rtw_change_bss, .change_bss = cfg80211_rtw_change_bss,
.mgmt_tx = cfg80211_rtw_mgmt_tx, .mgmt_tx = cfg80211_rtw_mgmt_tx,
.mgmt_frame_register = cfg80211_rtw_mgmt_frame_register,
#if defined(CONFIG_PNO_SUPPORT) #if defined(CONFIG_PNO_SUPPORT)
.sched_scan_start = cfg80211_rtw_sched_scan_start, .sched_scan_start = cfg80211_rtw_sched_scan_start,

View File

@@ -1217,33 +1217,31 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
return 0; return 0;
} }
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
u16 frame_type, bool reg) struct wireless_dev *wdev,
struct mgmt_frame_regs *upd)
{ {
struct wilc *wl = wiphy_priv(wiphy); struct wilc *wl = wiphy_priv(wiphy);
struct wilc_vif *vif = netdev_priv(wdev->netdev); 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) if (wl->initialized) {
return; bool prev = vif->mgmt_reg_stypes & presp_bit;
bool now = upd->interface_stypes & presp_bit;
switch (frame_type) { if (now != prev)
case IEEE80211_STYPE_PROBE_REQ: wilc_frame_register(vif, IEEE80211_STYPE_PROBE_REQ, now);
vif->frame_reg[0].type = frame_type;
vif->frame_reg[0].reg = reg;
break;
case IEEE80211_STYPE_ACTION: prev = vif->mgmt_reg_stypes & action_bit;
vif->frame_reg[1].type = frame_type; now = upd->interface_stypes & action_bit;
vif->frame_reg[1].reg = reg;
break;
default: if (now != prev)
break; wilc_frame_register(vif, IEEE80211_STYPE_ACTION, now);
} }
if (!wl->initialized) vif->mgmt_reg_stypes =
return; upd->interface_stypes & (presp_bit | action_bit);
wilc_frame_register(vif, frame_type, reg);
} }
static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, 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, .cancel_remain_on_channel = cancel_remain_on_channel,
.mgmt_tx_cancel_wait = mgmt_tx_cancel_wait, .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
.mgmt_tx = mgmt_tx, .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_power_mgmt = set_power_mgmt,
.set_cqm_rssi_config = set_cqm_rssi_config, .set_cqm_rssi_config = set_cqm_rssi_config,

View File

@@ -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, struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
const char *name, const char *name,
struct net_device *real_dev); struct net_device *real_dev);
void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
u16 frame_type, bool reg); struct wireless_dev *wdev,
struct mgmt_frame_regs *upd);
struct wilc_vif *wilc_get_interface(struct wilc *wl); struct wilc_vif *wilc_get_interface(struct wilc *wl);
struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl); struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl);
void wlan_deinit_locks(struct wilc *wilc); void wlan_deinit_locks(struct wilc *wilc);

View File

@@ -571,6 +571,7 @@ static int wilc_mac_open(struct net_device *ndev)
struct wilc *wl = vif->wilc; struct wilc *wl = vif->wilc;
unsigned char mac_add[ETH_ALEN] = {0}; unsigned char mac_add[ETH_ALEN] = {0};
int ret = 0; int ret = 0;
struct mgmt_frame_regs mgmt_regs = {};
if (!wl || !wl->dev) { if (!wl || !wl->dev) {
netdev_err(ndev, "device not ready\n"); netdev_err(ndev, "device not ready\n");
@@ -602,14 +603,12 @@ static int wilc_mac_open(struct net_device *ndev)
return -EINVAL; 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->ndev->ieee80211_ptr,
vif->frame_reg[0].type, &mgmt_regs);
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);
netif_wake_queue(ndev); netif_wake_queue(ndev);
wl->open_ifcs++; wl->open_ifcs++;
vif->mac_opened = 1; 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); srcu_idx = srcu_read_lock(&wilc->srcu);
list_for_each_entry_rcu(vif, &wilc->vif_list, list) { list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
u16 type = le16_to_cpup((__le16 *)buff); u16 type = le16_to_cpup((__le16 *)buff);
u32 type_bit = BIT(type >> 4);
if (vif->priv.p2p_listen_state && if (vif->priv.p2p_listen_state &&
((type == vif->frame_reg[0].type && vif->mgmt_reg_stypes & type_bit)
vif->frame_reg[0].reg) ||
(type == vif->frame_reg[1].type &&
vif->frame_reg[1].reg)))
wilc_wfi_p2p_rx(vif, buff, size); wilc_wfi_p2p_rx(vif, buff, size);
if (vif->monitor_flag) if (vif->monitor_flag)

View File

@@ -24,8 +24,6 @@
#define PMKID_FOUND 1 #define PMKID_FOUND 1
#define NUM_STA_ASSOCIATED 8 #define NUM_STA_ASSOCIATED 8
#define NUM_REG_FRAME 2
#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 #define TCP_ACK_FILTER_LINK_SPEED_THRESH 54
#define DEFAULT_LINK_SPEED 72 #define DEFAULT_LINK_SPEED 72
@@ -151,11 +149,6 @@ struct wilc_priv {
u64 inc_roc_cookie; u64 inc_roc_cookie;
}; };
struct frame_reg {
u16 type;
bool reg;
};
#define MAX_TCP_SESSION 25 #define MAX_TCP_SESSION 25
#define MAX_PENDING_ACKS 256 #define MAX_PENDING_ACKS 256
@@ -187,7 +180,7 @@ struct wilc_vif {
u8 iftype; u8 iftype;
int monitor_flag; int monitor_flag;
int mac_opened; int mac_opened;
struct frame_reg frame_reg[NUM_REG_FRAME]; u32 mgmt_reg_stypes;
struct net_device_stats netstats; struct net_device_stats netstats;
struct wilc *wilc; struct wilc *wilc;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];

View File

@@ -9,7 +9,7 @@
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
* Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 - 2017 Intel Deutschland GmbH * Copyright (c) 2016 - 2017 Intel Deutschland GmbH
* Copyright (c) 2018 - 2019 Intel Corporation * Copyright (c) 2018 - 2020 Intel Corporation
*/ */
#ifndef LINUX_IEEE80211_H #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_40MHZ: 40 MHz channel width
* @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 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_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 * @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask
* (the NSS value is the value of this field + 1) * (the NSS value is the value of this field + 1)
* @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift * @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 * using a beamforming steering matrix
*/ */
enum ieee80211_vht_opmode_bits { 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_20MHZ = 0,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1, IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ = 1,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2, IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ = 2,
IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3, 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_MASK = 0x70,
IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4, IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT = 4,
IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80, IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF = 0x80,
@@ -1065,6 +1067,7 @@ struct ieee80211_mgmt {
/* Supported rates membership selectors */ /* Supported rates membership selectors */
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
/* mgmt header + 1 byte category code */ /* mgmt header + 1 byte category code */
#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u) #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 * @ext_nss_bw_capable: indicates whether or not the local transmitter
* (rate scaling algorithm) can deal with the new logic * (rate scaling algorithm) can deal with the new logic
* (dot11VHTExtendedNSSBWCapable) * (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 * Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can
* vary for a given BW/MCS. This function parses the data. * 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, int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
enum ieee80211_vht_chanwidth bw, 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 */ /* 802.11ax HE MAC capabilities */
#define IEEE80211_HE_MAC_CAP0_HTC_HE 0x01 #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_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) #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 * ieee80211_action_contains_tpc - checks if the frame contains TPC element
* @skb: the skb containing the frame, length will be checked * @skb: the skb containing the frame, length will be checked

View File

@@ -128,6 +128,7 @@ enum ieee80211_channel_flags {
* with cfg80211. * with cfg80211.
* *
* @center_freq: center frequency in MHz * @center_freq: center frequency in MHz
* @freq_offset: offset from @center_freq, in KHz
* @hw_value: hardware-specific value for the channel * @hw_value: hardware-specific value for the channel
* @flags: channel flags from &enum ieee80211_channel_flags. * @flags: channel flags from &enum ieee80211_channel_flags.
* @orig_flags: channel flags at registration time, used by regulatory * @orig_flags: channel flags at registration time, used by regulatory
@@ -149,6 +150,7 @@ enum ieee80211_channel_flags {
struct ieee80211_channel { struct ieee80211_channel {
enum nl80211_band band; enum nl80211_band band;
u32 center_freq; u32 center_freq;
u16 freq_offset;
u16 hw_value; u16 hw_value;
u32 flags; u32 flags;
int max_antenna_gain; int max_antenna_gain;
@@ -617,6 +619,7 @@ struct key_params {
* If edmg is requested (i.e. the .channels member is non-zero), * If edmg is requested (i.e. the .channels member is non-zero),
* chan will define the primary channel and all other * chan will define the primary channel and all other
* parameters are ignored. * parameters are ignored.
* @freq1_offset: offset from @center_freq1, in KHz
*/ */
struct cfg80211_chan_def { struct cfg80211_chan_def {
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
@@ -624,6 +627,7 @@ struct cfg80211_chan_def {
u32 center_freq1; u32 center_freq1;
u32 center_freq2; u32 center_freq2;
struct ieee80211_edmg edmg; 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 && return (chandef1->chan == chandef2->chan &&
chandef1->width == chandef2->width && chandef1->width == chandef2->width &&
chandef1->center_freq1 == chandef2->center_freq1 && chandef1->center_freq1 == chandef2->center_freq1 &&
chandef1->freq1_offset == chandef2->freq1_offset &&
chandef1->center_freq2 == chandef2->center_freq2); chandef1->center_freq2 == chandef2->center_freq2);
} }
@@ -1054,6 +1059,7 @@ enum cfg80211_ap_settings_flags {
* @ht_required: stations must support HT * @ht_required: stations must support HT
* @vht_required: stations must support VHT * @vht_required: stations must support VHT
* @twt_responder: Enable Target Wait Time * @twt_responder: Enable Target Wait Time
* @he_required: stations must support HE
* @flags: flags, as defined in enum cfg80211_ap_settings_flags * @flags: flags, as defined in enum cfg80211_ap_settings_flags
* @he_obss_pd: OBSS Packet Detection settings * @he_obss_pd: OBSS Packet Detection settings
* @he_bss_color: BSS Color 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_vht_cap *vht_cap;
const struct ieee80211_he_cap_elem *he_cap; const struct ieee80211_he_cap_elem *he_cap;
const struct ieee80211_he_operation *he_oper; const struct ieee80211_he_operation *he_oper;
bool ht_required, vht_required; bool ht_required, vht_required, he_required;
bool twt_responder; bool twt_responder;
u32 flags; u32 flags;
struct ieee80211_he_obss_pd he_obss_pd; struct ieee80211_he_obss_pd he_obss_pd;
@@ -3384,6 +3390,21 @@ struct cfg80211_update_owe_info {
size_t ie_len; 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 * 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 * The driver should not call cfg80211_sched_scan_stopped() for a requested
* stop (when this method returns 0). * stop (when this method returns 0).
* *
* @mgmt_frame_register: Notify driver that a management frame type was * @update_mgmt_frame_registrations: Notify the driver that management frame
* registered. The callback is allowed to sleep. * registrations were updated. The callback is allowed to sleep.
* *
* @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. * @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 * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
@@ -3932,9 +3953,9 @@ struct cfg80211_ops {
struct net_device *dev, struct net_device *dev,
u32 rate, u32 pkts, u32 intvl); 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, 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 (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
int (*get_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 * by cfg80211 on change_interface
* @mgmt_registrations: list of registrations for management frames * @mgmt_registrations: list of registrations for management frames
* @mgmt_registrations_lock: lock for the list * @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 * @mtx: mutex used to lock data in this struct, may be used by drivers
* and some API functions require it held * and some API functions require it held
* @beacon_interval: beacon interval used on this device for transmitting * @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_list: (private) peer measurement requests
* @pmsr_lock: (private) peer measurements requests/results lock * @pmsr_lock: (private) peer measurements requests/results lock
* @pmsr_free_wk: (private) peer measurements cleanup work * @pmsr_free_wk: (private) peer measurements cleanup work
* @unprot_beacon_reported: (private) timestamp of last
* unprotected beacon report
*/ */
struct wireless_dev { struct wireless_dev {
struct wiphy *wiphy; struct wiphy *wiphy;
@@ -5058,6 +5082,7 @@ struct wireless_dev {
struct list_head mgmt_registrations; struct list_head mgmt_registrations;
spinlock_t mgmt_registrations_lock; spinlock_t mgmt_registrations_lock;
struct work_struct mgmt_registrations_update_wk;
struct mutex mtx; struct mutex mtx;
@@ -5121,6 +5146,8 @@ struct wireless_dev {
struct list_head pmsr_list; struct list_head pmsr_list;
spinlock_t pmsr_lock; spinlock_t pmsr_lock;
struct work_struct pmsr_free_wk; struct work_struct pmsr_free_wk;
unsigned long unprot_beacon_reported;
}; };
static inline u8 *wdev_address(struct wireless_dev *wdev) 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. * 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 * ieee80211_channel_to_frequency - convert channel number to frequency
* @chan: channel number * @chan: channel number
* @band: band, necessary due to channel number overlap * @band: band, necessary due to channel number overlap
* Return: The corresponding frequency (in MHz), or 0 if the conversion failed. * 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 * 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. * 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 * ieee80211_get_channel - get channel struct from wiphy for specified frequency
* *
* @wiphy: the struct wiphy to get the channel for * @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. * 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 * 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 * cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
* @dev: network device * @dev: network device
* @buf: deauthentication frame (header + body) * @buf: received management frame (header + body)
* @len: length of the frame data * @len: length of the frame data
* *
* This function is called whenever a received deauthentication or dissassoc * 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 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, void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev,
const u8 *buf, size_t len); 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, bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
u8 *op_class); 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 * cfg80211_tdls_oper_request - request userspace to perform TDLS operation
* @dev: the device on which the operation is requested * @dev: the device on which the operation is requested

View File

@@ -508,6 +508,7 @@ struct ieee80211_ftm_responder_params {
* mode only, set if the AP advertises TWT responder role) * mode only, set if the AP advertises TWT responder role)
* @twt_responder: does this BSS support TWT requester (relevant for managed * @twt_responder: does this BSS support TWT requester (relevant for managed
* mode only, set if the AP advertises TWT responder role) * mode only, set if the AP advertises TWT responder role)
* @twt_protected: does this BSS support protected TWT frames
* @assoc: association status * @assoc: association status
* @ibss_joined: indicates whether this station is part of an IBSS * @ibss_joined: indicates whether this station is part of an IBSS
* or not * or not
@@ -603,7 +604,7 @@ struct ieee80211_ftm_responder_params {
* nontransmitted BSSIDs * nontransmitted BSSIDs
* @profile_periodicity: the least number of beacon frames need to be received * @profile_periodicity: the least number of beacon frames need to be received
* in order to discover all the nontransmitted BSSIDs in the set. * 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_obss_pd: OBSS Packet Detection parameters.
* @he_bss_color: BSS coloring settings, if BSS supports HE * @he_bss_color: BSS coloring settings, if BSS supports HE
*/ */
@@ -618,6 +619,7 @@ struct ieee80211_bss_conf {
bool he_support; bool he_support;
bool twt_requester; bool twt_requester;
bool twt_responder; bool twt_responder;
bool twt_protected;
/* association related data */ /* association related data */
bool assoc, ibss_joined; bool assoc, ibss_joined;
bool ibss_creator; bool ibss_creator;
@@ -666,7 +668,10 @@ struct ieee80211_bss_conf {
u8 bssid_indicator; u8 bssid_indicator;
bool ema_ap; bool ema_ap;
u8 profile_periodicity; 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 ieee80211_he_obss_pd he_obss_pd;
struct cfg80211_he_bss_color he_bss_color; 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_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_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_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. * 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 * @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 * This field must be set for management frames, but isn't strictly needed
* for data (other) frames - for those it only affects radiotap reporting. * 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 * @signal: signal strength when receiving this frame, either in dBm, in dB or
* unspecified depending on the hardware capabilities flags * unspecified depending on the hardware capabilities flags
* @IEEE80211_HW_SIGNAL_* * @IEEE80211_HW_SIGNAL_*
@@ -1363,7 +1371,7 @@ struct ieee80211_rx_status {
u32 device_timestamp; u32 device_timestamp;
u32 ampdu_reference; u32 ampdu_reference;
u32 flag; u32 flag;
u16 freq; u16 freq: 13, freq_offset: 1;
u8 enc_flags; u8 enc_flags;
u8 encoding:2, bw:3, he_ru:3; u8 encoding:2, bw:3, he_ru:3;
u8 he_gi:2, he_dcm:1; u8 he_gi:2, he_dcm:1;
@@ -1379,6 +1387,13 @@ struct ieee80211_rx_status {
u8 zero_length_psdu_type; 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 * struct ieee80211_vendor_radiotap - vendor radiotap data information
* @present: presence bitmap for this vendor namespace * @present: presence bitmap for this vendor namespace
@@ -1620,6 +1635,8 @@ enum ieee80211_vif_flags {
* monitor interface (if that is requested.) * monitor interface (if that is requested.)
* @probe_req_reg: probe requests should be reported to mac80211 for this * @probe_req_reg: probe requests should be reported to mac80211 for this
* interface. * 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 * @drv_priv: data area for driver use, will always be aligned to
* sizeof(void \*). * sizeof(void \*).
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction) * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
@@ -1647,7 +1664,8 @@ struct ieee80211_vif {
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
#endif #endif
unsigned int probe_req_reg; bool probe_req_reg;
bool rx_mcast_action_reg;
bool txqs_stopped[IEEE80211_NUM_ACS]; 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_PSPOLL: pass PS Poll frames
* *
* @FIF_PROBE_REQ: pass probe request frames * @FIF_PROBE_REQ: pass probe request frames
*
* @FIF_MCAST_ACTION: pass multicast Action frames
*/ */
enum ieee80211_filter_flags { enum ieee80211_filter_flags {
FIF_ALLMULTI = 1<<1, FIF_ALLMULTI = 1<<1,
@@ -3101,6 +3121,7 @@ enum ieee80211_filter_flags {
FIF_OTHER_BSS = 1<<6, FIF_OTHER_BSS = 1<<6,
FIF_PSPOLL = 1<<7, FIF_PSPOLL = 1<<7,
FIF_PROBE_REQ = 1<<8, 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_START: start RX aggregation
* @IEEE80211_AMPDU_RX_STOP: stop RX aggregation * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation
* @IEEE80211_AMPDU_TX_START: start TX aggregation, the driver must either * @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. * status %IEEE80211_AMPDU_TX_START_IMMEDIATE.
* @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational
* @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting * @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_IMMEDIATE 1
#define IEEE80211_AMPDU_TX_START_DELAY_ADDBA 2
/** /**
* struct ieee80211_ampdu_params - AMPDU action parameters * struct ieee80211_ampdu_params - AMPDU action parameters

View File

@@ -231,13 +231,6 @@ struct ieee80211_regdomain {
struct ieee80211_reg_rule reg_rules[]; 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) \ #define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \
{ \ { \
.freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \

View File

@@ -687,6 +687,10 @@
* four bytes for vendor frames including the OUI. The registration * four bytes for vendor frames including the OUI. The registration
* cannot be dropped, but is removed automatically when the netlink * cannot be dropped, but is removed automatically when the netlink
* socket is closed. Multiple registrations can be made. * 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 * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
* backward compatibility * backward compatibility
* @NL80211_CMD_FRAME: Management frame TX request and RX notification. This * @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 * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
* is passed using %NL80211_ATTR_TID_CONFIG attribute. * 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_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@@ -1377,6 +1386,8 @@ enum nl80211_commands {
NL80211_CMD_SET_TID_CONFIG, NL80211_CMD_SET_TID_CONFIG,
NL80211_CMD_UNPROT_BEACON,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
@@ -2470,6 +2481,9 @@ enum nl80211_commands {
* no roaming occurs between the reauth threshold and PMK expiration, * no roaming occurs between the reauth threshold and PMK expiration,
* disassociation is still forced. * 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 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2945,6 +2959,8 @@ enum nl80211_attrs {
NL80211_ATTR_PMK_LIFETIME, NL80211_ATTR_PMK_LIFETIME,
NL80211_ATTR_PMK_REAUTH_THRESHOLD, NL80211_ATTR_PMK_REAUTH_THRESHOLD,
NL80211_ATTR_RECEIVE_MULTICAST,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@@ -5674,6 +5690,8 @@ enum nl80211_feature_flags {
* *
* @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
* and can receive key configuration for BIGTK using key indexes 6 and 7. * 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 * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
* forwarding of preauth frames over the control port. They are then * 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 * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
* in IBSS mode, essentially by dropping their state. * 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. * @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index. * @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_CONTROL_PORT_NO_PREAUTH,
NL80211_EXT_FEATURE_PROTECTED_TWT, NL80211_EXT_FEATURE_PROTECTED_TWT,
NL80211_EXT_FEATURE_DEL_IBSS_STA, NL80211_EXT_FEATURE_DEL_IBSS_STA,
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
/* add new features before the definition below */ /* add new features before the definition below */
NUM_NL80211_EXT_FEATURES, NUM_NL80211_EXT_FEATURES,

View File

@@ -9,7 +9,7 @@
* Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation * Copyright 2007-2010, Intel Corporation
* Copyright(c) 2015-2017 Intel Deutschland GmbH * Copyright(c) 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018 - 2019 Intel Corporation * Copyright (C) 2018 - 2020 Intel Corporation
*/ */
#include <linux/ieee80211.h> #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); 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_sub_if_data *sdata = sta->sdata;
struct ieee80211_ampdu_params params = { struct ieee80211_local *local = sta->local;
.sta = &sta->sta, u8 tid = tid_tx->tid;
.action = IEEE80211_AMPDU_TX_START,
.tid = tid,
.buf_size = 0,
.amsdu = false,
.timeout = 0,
};
int ret;
u16 buf_size; 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, &params);
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 */ /* activate the timer for the recipient's addBA response */
mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n", 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 */ /* send AddBA request */
ieee80211_send_addba_request(sdata, sta->sta.addr, tid, 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); 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, &params);
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))) if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
return; 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)) if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
ieee80211_agg_tx_operational(local, sta, tid); ieee80211_agg_tx_operational(local, sta, tid);
} }

View File

@@ -994,7 +994,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
BSS_CHANGED_TWT | BSS_CHANGED_TWT |
BSS_CHANGED_HE_OBSS_PD | BSS_CHANGED_HE_OBSS_PD |
BSS_CHANGED_HE_BSS_COLOR; BSS_CHANGED_HE_BSS_COLOR;
int err; int i, err;
int prev_beacon_int; int prev_beacon_int;
old = sdata_dereference(sdata->u.ap.beacon, sdata); 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 |= sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
IEEE80211_P2P_OPPPS_ENABLE_BIT; 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, &params->beacon, NULL); err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
if (err < 0) { if (err < 0) {
ieee80211_vif_release_channel(sdata); 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); ieee80211_free_keys(sdata, true);
sdata->vif.bss_conf.enable_beacon = false; sdata->vif.bss_conf.enable_beacon = false;
sdata->beacon_rate_set = false;
sdata->vif.bss_conf.ssid_len = 0; sdata->vif.bss_conf.ssid_len = 0;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); 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; const u8 *old_ie;
struct ieee80211_sub_if_data *sdata = container_of(ifmsh, struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
struct ieee80211_sub_if_data, u.mesh); struct ieee80211_sub_if_data, u.mesh);
int i;
/* allocate information elements */ /* allocate information elements */
new_ie = NULL; 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.beacon_int = setup->beacon_interval;
sdata->vif.bss_conf.dtim_period = setup->dtim_period; 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; return 0;
} }
@@ -3287,6 +3311,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
goto out; 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); chanctx = container_of(conf, struct ieee80211_chanctx, conf);
ch_switch.timestamp = 0; ch_switch.timestamp = 0;
@@ -3398,41 +3428,43 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
return 0; 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, struct wireless_dev *wdev,
u16 frame_type, bool reg) struct mgmt_frame_regs *upd)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 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) { global_change =
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: (local->probe_req_reg != !!(upd->global_stypes & preq_mask)) ||
if (reg) { (local->rx_mcast_action_reg !=
local->probe_req_reg++; !!(upd->global_mcast_stypes & action_mask));
sdata->vif.probe_req_reg++; local->probe_req_reg = upd->global_stypes & preq_mask;
} else { local->rx_mcast_action_reg = upd->global_mcast_stypes & action_mask;
if (local->probe_req_reg)
local->probe_req_reg--;
if (sdata->vif.probe_req_reg) intf_change = (sdata->vif.probe_req_reg !=
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) if (!local->open_count)
break; return;
if (sdata->vif.probe_req_reg == 1) if (intf_change && ieee80211_sdata_running(sdata))
drv_config_iface_filter(local, sdata, FIF_PROBE_REQ, drv_config_iface_filter(local, sdata,
FIF_PROBE_REQ); sdata->vif.probe_req_reg ?
else if (sdata->vif.probe_req_reg == 0) FIF_PROBE_REQ : 0,
drv_config_iface_filter(local, sdata, 0,
FIF_PROBE_REQ); FIF_PROBE_REQ);
if (global_change)
ieee80211_configure_filter(local); ieee80211_configure_filter(local);
break;
default:
break;
}
} }
static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) 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, .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_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, .set_antenna = ieee80211_set_antenna,
.get_antenna = ieee80211_get_antenna, .get_antenna = ieee80211_get_antenna,
.set_rekey_data = ieee80211_set_rekey_data, .set_rekey_data = ieee80211_set_rekey_data,

View File

@@ -533,6 +533,7 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
struct cfg80211_chan_def *chandef = &local->_oper_chandef; struct cfg80211_chan_def *chandef = &local->_oper_chandef;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT; chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = chandef->chan->center_freq; chandef->center_freq1 = chandef->chan->center_freq;
chandef->freq1_offset = chandef->chan->freq_offset;
chandef->center_freq2 = 0; chandef->center_freq2 = 0;
/* NOTE: Disabling radar is only valid here for /* NOTE: Disabling radar is only valid here for

View File

@@ -236,7 +236,7 @@ IEEE80211_IF_FILE_R(hw_queues);
/* STA attributes */ /* STA attributes */
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); 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); IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,

View File

@@ -57,17 +57,14 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
void void
ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif, 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 = memset(&vif->bss_conf.he_oper, 0, sizeof(vif->bss_conf.he_oper));
&vif->bss_conf.he_operation; if (!he_op_ie)
if (!he_op_ie_elem) {
memset(he_operation, 0, sizeof(*he_operation));
return; 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 void

View File

@@ -1758,6 +1758,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int i; int i;
int ret; int ret;
if (params->chandef.chan->freq_offset) {
/* this may work, but is untested */
return -EOPNOTSUPP;
}
ret = cfg80211_chandef_dfs_required(local->hw.wiphy, ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
&params->chandef, &params->chandef,
sdata->wdev.iftype); sdata->wdev.iftype);

View File

@@ -450,8 +450,6 @@ struct ieee80211_if_managed {
u8 bssid[ETH_ALEN] __aligned(2); u8 bssid[ETH_ALEN] __aligned(2);
u16 aid;
bool powersave; /* powersave requested for this iface */ bool powersave; /* powersave requested for this iface */
bool broken_ap; /* AP is broken -- turn off powersave */ bool broken_ap; /* AP is broken -- turn off powersave */
bool have_beacon; bool have_beacon;
@@ -964,6 +962,10 @@ struct ieee80211_sub_if_data {
bool rc_has_vht_mcs_mask[NUM_NL80211_BANDS]; bool rc_has_vht_mcs_mask[NUM_NL80211_BANDS];
u16 rc_rateidx_vht_mcs_mask[NUM_NL80211_BANDS][NL80211_VHT_NSS_MAX]; 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 { union {
struct ieee80211_if_ap ap; struct ieee80211_if_ap ap;
struct ieee80211_if_wds wds; struct ieee80211_if_wds wds;
@@ -1169,7 +1171,8 @@ struct ieee80211_local {
/* number of interfaces with corresponding FIF_ flags */ /* number of interfaces with corresponding FIF_ flags */
int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll, int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
fif_probe_req; fif_probe_req;
int probe_req_reg; bool probe_req_reg;
bool rx_mcast_action_reg;
unsigned int filter_flags; /* FIF_* */ unsigned int filter_flags; /* FIF_* */
bool wiphy_ciphers_allocated; bool wiphy_ciphers_allocated;

View File

@@ -644,6 +644,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
local->fif_probe_req++; 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 && if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
sdata->vif.type != NL80211_IFTYPE_NAN) sdata->vif.type != NL80211_IFTYPE_NAN)
changed |= ieee80211_reset_erp_info(sdata); changed |= ieee80211_reset_erp_info(sdata);

View File

@@ -64,6 +64,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
if (local->fif_pspoll) if (local->fif_pspoll)
new_flags |= FIF_PSPOLL; new_flags |= FIF_PSPOLL;
if (local->rx_mcast_action_reg)
new_flags |= FIF_MCAST_ACTION;
spin_lock_bh(&local->filter_lock); spin_lock_bh(&local->filter_lock);
changed_flags = local->filter_flags ^ new_flags; 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.chan = local->tmp_channel;
chandef.width = NL80211_CHAN_WIDTH_20_NOHT; chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
chandef.center_freq1 = chandef.chan->center_freq; chandef.center_freq1 = chandef.chan->center_freq;
chandef.freq1_offset = chandef.chan->freq_offset;
} else } else
chandef = local->_oper_chandef; chandef = local->_oper_chandef;
WARN(!cfg80211_chandef_valid(&chandef), WARN(!cfg80211_chandef_valid(&chandef),
"control:%d MHz width:%d center: %d/%d MHz", "control:%d.%03d MHz width:%d center: %d.%03d/%d MHz",
chandef.chan->center_freq, chandef.width, chandef.chan->center_freq, chandef.chan->freq_offset,
chandef.center_freq1, chandef.center_freq2); chandef.width, chandef.center_freq1, chandef.freq1_offset,
chandef.center_freq2);
if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef)) if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef))
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;

View File

@@ -994,6 +994,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
/* stop the beacon */ /* stop the beacon */
ifmsh->mesh_id_len = 0; ifmsh->mesh_id_len = 0;
sdata->vif.bss_conf.enable_beacon = false; sdata->vif.bss_conf.enable_beacon = false;
sdata->beacon_rate_set = false;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);

View File

@@ -162,6 +162,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
chandef->chan = channel; chandef->chan = channel;
chandef->width = NL80211_CHAN_WIDTH_20_NOHT; chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
chandef->center_freq1 = channel->center_freq; chandef->center_freq1 = channel->center_freq;
chandef->freq1_offset = channel->freq_offset;
if (!ht_oper || !sta_ht_cap.ht_supported) { if (!ht_oper || !sta_ht_cap.ht_supported) {
ret = IEEE80211_STA_DISABLE_HT | ret = IEEE80211_STA_DISABLE_HT |
@@ -396,9 +397,12 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
return 0; return 0;
sdata_info(sdata, sdata_info(sdata,
"AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n", "AP %pM changed bandwidth, new config is %d.%03d MHz, "
ifmgd->bssid, chandef.chan->center_freq, chandef.width, "width %d (%d.%03d/%d MHz)\n",
chandef.center_freq1, chandef.center_freq2); 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 | if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
IEEE80211_STA_DISABLE_VHT | 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, if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
IEEE80211_CHAN_DISABLED)) { IEEE80211_CHAN_DISABLED)) {
sdata_info(sdata, 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, ifmgd->associated->bssid,
csa_ie.chandef.chan->center_freq, csa_ie.chandef.chan->center_freq,
csa_ie.chandef.chan->freq_offset,
csa_ie.chandef.width, csa_ie.chandef.center_freq1, csa_ie.chandef.width, csa_ie.chandef.center_freq1,
csa_ie.chandef.freq1_offset,
csa_ie.chandef.center_freq2); csa_ie.chandef.center_freq2);
ieee80211_queue_work(&local->hw, ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work); &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) { 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", sdata_info(sdata, "%pM denied authentication (status %d)\n",
mgmt->sa, status_code); mgmt->sa, status_code);
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
event.u.mlme.status = MLME_DENIED; event.u.mlme.status = MLME_DENIED;
event.u.mlme.reason = status_code; event.u.mlme.reason = status_code;
drv_event_callback(sdata->local, sdata, &event); 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; *have_higher_than_11mbit = true;
/* /*
* Skip HT and VHT BSS membership selectors since they're not * Skip HT, VHT and HE BSS membership selectors since they're
* rates. * not rates.
* *
* Note: Even though the membership selector and the basic * Note: Even though the membership selector and the basic
* rate flag share the same bit, they are not exactly * rate flag share the same bit, they are not exactly
* the same. * the same.
*/ */
if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) || 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; continue;
for (j = 0; j < sband->n_bitrates; j++) { 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; return false;
} }
ifmgd->aid = aid; sdata->vif.bss_conf.aid = aid;
ifmgd->tdls_chan_switch_prohibited = ifmgd->tdls_chan_switch_prohibited =
elems->ext_capab && elems->ext_capab_len >= 5 && elems->ext_capab && elems->ext_capab_len >= 5 &&
(elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); (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); sta);
bss_conf->he_support = sta->sta.he_cap.has_he; 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); changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
} else { } else {
bss_conf->he_support = false; bss_conf->he_support = false;
bss_conf->twt_requester = false; bss_conf->twt_requester = false;
bss_conf->twt_protected = false;
} }
if (bss_conf->he_support) { 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; 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 */ * ieee80211_set_associated() will tell the driver */
bss_conf->aid = aid;
bss_conf->assoc_capability = capab_info; bss_conf->assoc_capability = capab_info;
ieee80211_set_associated(sdata, cbss, changed); 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); 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) if (!channel)
return; return;
@@ -3877,7 +3900,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
return; 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(); rcu_read_unlock();
return; return;
} }
@@ -3948,7 +3972,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
mgmt->bssid, bssid); mgmt->bssid, bssid);
if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && 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.dynamic_ps_timeout > 0) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) { if (local->hw.conf.flags & IEEE80211_CONF_PS) {
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 * doesn't happen any more, but keep the workaround so
* in case some *other* APs are buggy in different ways * in case some *other* APs are buggy in different ways
* we can connect -- with a warning. * 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, sdata_info(sdata,
"No basic rates, using min rate instead\n"); "No basic rates, using min rate instead\n");
basic_rates = BIT(min_rate_index); basic_rates = BIT(min_rate_index);

View File

@@ -557,6 +557,10 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
lockdep_assert_held(&local->mtx); 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) if (local->use_chanctx && !local->ops->remain_on_channel)
return -EOPNOTSUPP; return -EOPNOTSUPP;

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org> * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2019-2020 Intel Corporation
*/ */
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/types.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_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); 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++) { for(i = 0; i < MAX_THR_RATES; i++) {
minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i], minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i],
tmp_mcs_tp_rate); tmp_mcs_tp_rate);

View File

@@ -412,6 +412,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
pos++; pos++;
/* IEEE80211_RADIOTAP_CHANNEL */ /* IEEE80211_RADIOTAP_CHANNEL */
/* TODO: frequency offset in KHz */
put_unaligned_le16(status->freq, pos); put_unaligned_le16(status->freq, pos);
pos += 2; pos += 2;
if (status->bw == RATE_INFO_BW_10) 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 || if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
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 */ return RX_DROP_MONITOR; /* unexpected BIP keyidx */
}
rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx); rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
if (!rx->key) 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 */ /* either the frame has been decrypted or will be dropped */
status->flag |= RX_FLAG_DECRYPTED; 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; return result;
} }
@@ -2411,8 +2420,12 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
return -EACCES; return -EACCES;
} }
if (unlikely(ieee80211_is_beacon(fc) && rx->key && 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; return -EACCES;
}
/* /*
* When using MFP, Action frames are not allowed prior to * When using MFP, Action frames are not allowed prior to
* having configured keys. * having configured keys.

View File

@@ -275,7 +275,8 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
return; 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) if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return; return;
@@ -896,6 +897,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
local->scan_chandef.chan = chan; local->scan_chandef.chan = chan;
local->scan_chandef.center_freq1 = chan->center_freq; local->scan_chandef.center_freq1 = chan->center_freq;
local->scan_chandef.freq1_offset = chan->freq_offset;
local->scan_chandef.center_freq2 = 0; local->scan_chandef.center_freq2 = 0;
switch (scan_req->scan_width) { switch (scan_req->scan_width) {
case NL80211_BSS_CHAN_WIDTH_5: case NL80211_BSS_CHAN_WIDTH_5:

View File

@@ -3,6 +3,7 @@
* Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2002-2005, Devicescape Software, Inc.
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright(c) 2015-2017 Intel Deutschland GmbH * Copyright(c) 2015-2017 Intel Deutschland GmbH
* Copyright(c) 2020 Intel Corporation
*/ */
#ifndef STA_INFO_H #ifndef STA_INFO_H
@@ -68,6 +69,8 @@
* @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP. * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP.
* @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX * @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX
* until pending frames are delivered * 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 * @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_WANT_STOP 5
#define HT_AGG_STATE_START_CB 6 #define HT_AGG_STATE_START_CB 6
#define HT_AGG_STATE_STOP_CB 7 #define HT_AGG_STATE_STOP_CB 7
#define HT_AGG_STATE_SENT_ADDBA 8
DECLARE_EWMA(avg_signal, 10, 8) DECLARE_EWMA(avg_signal, 10, 8)
enum ieee80211_agg_stop_reason { enum ieee80211_agg_stop_reason {

View File

@@ -226,12 +226,11 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
static void static void
ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) 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); u8 *pos = skb_put(skb, 4);
*pos++ = WLAN_EID_AID; *pos++ = WLAN_EID_AID;
*pos++ = 2; /* len */ *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 */ /* 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; u32 ch_sw_tm_ie;
int ret; int ret;
if (chandef->chan->freq_offset)
/* this may work, but is untested */
return -EOPNOTSUPP;
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
sta = sta_info_get(sdata, addr); sta = sta_info_get(sdata, addr);
if (!sta) { if (!sta) {

View File

@@ -37,32 +37,42 @@
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" #define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
#define CHANDEF_ENTRY __field(u32, control_freq) \ #define CHANDEF_ENTRY __field(u32, control_freq) \
__field(u32, freq_offset) \
__field(u32, chan_width) \ __field(u32, chan_width) \
__field(u32, center_freq1) \ __field(u32, center_freq1) \
__field(u32, freq1_offset) \
__field(u32, center_freq2) __field(u32, center_freq2)
#define CHANDEF_ASSIGN(c) \ #define CHANDEF_ASSIGN(c) \
__entry->control_freq = (c) ? ((c)->chan ? (c)->chan->center_freq : 0) : 0; \ __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->chan_width = (c) ? (c)->width : 0; \
__entry->center_freq1 = (c) ? (c)->center_freq1 : 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; __entry->center_freq2 = (c) ? (c)->center_freq2 : 0;
#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz" #define CHANDEF_PR_FMT " control:%d.%03d MHz width:%d center: %d.%03d/%d MHz"
#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \ #define CHANDEF_PR_ARG __entry->control_freq, __entry->freq_offset, __entry->chan_width, \
__entry->center_freq1, __entry->center_freq2 __entry->center_freq1, __entry->freq1_offset, __entry->center_freq2
#define MIN_CHANDEF_ENTRY \ #define MIN_CHANDEF_ENTRY \
__field(u32, min_control_freq) \ __field(u32, min_control_freq) \
__field(u32, min_freq_offset) \
__field(u32, min_chan_width) \ __field(u32, min_chan_width) \
__field(u32, min_center_freq1) \ __field(u32, min_center_freq1) \
__field(u32, min_freq1_offset) \
__field(u32, min_center_freq2) __field(u32, min_center_freq2)
#define MIN_CHANDEF_ASSIGN(c) \ #define MIN_CHANDEF_ASSIGN(c) \
__entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0; \ __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_chan_width = (c)->width; \
__entry->min_center_freq1 = (c)->center_freq1; \ __entry->min_center_freq1 = (c)->center_freq1; \
__entry->freq1_offset = (c)->freq1_offset; \
__entry->min_center_freq2 = (c)->center_freq2; __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_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_chan_width, \ #define MIN_CHANDEF_PR_ARG __entry->min_control_freq, __entry->min_freq_offset, \
__entry->min_center_freq1, __entry->min_center_freq2 __entry->min_chan_width, \
__entry->min_center_freq1, __entry->min_freq1_offset, \
__entry->min_center_freq2
#define CHANCTX_ENTRY CHANDEF_ENTRY \ #define CHANCTX_ENTRY CHANDEF_ENTRY \
MIN_CHANDEF_ENTRY \ MIN_CHANDEF_ENTRY \
@@ -412,6 +422,7 @@ TRACE_EVENT(drv_bss_info_changed,
__field(s32, cqm_rssi_hyst) __field(s32, cqm_rssi_hyst)
__field(u32, channel_width) __field(u32, channel_width)
__field(u32, channel_cfreq1) __field(u32, channel_cfreq1)
__field(u32, channel_cfreq1_offset)
__dynamic_array(u32, arp_addr_list, __dynamic_array(u32, arp_addr_list,
info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
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->cqm_rssi_hyst = info->cqm_rssi_hyst;
__entry->channel_width = info->chandef.width; __entry->channel_width = info->chandef.width;
__entry->channel_cfreq1 = info->chandef.center_freq1; __entry->channel_cfreq1 = info->chandef.center_freq1;
__entry->channel_cfreq1_offset = info->chandef.freq1_offset;
__entry->arp_addr_cnt = info->arp_addr_cnt; __entry->arp_addr_cnt = info->arp_addr_cnt;
memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list, memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ? sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
@@ -1223,6 +1235,7 @@ TRACE_EVENT(drv_remain_on_channel,
LOCAL_ENTRY LOCAL_ENTRY
VIF_ENTRY VIF_ENTRY
__field(int, center_freq) __field(int, center_freq)
__field(int, freq_offset)
__field(unsigned int, duration) __field(unsigned int, duration)
__field(u32, type) __field(u32, type)
), ),
@@ -1231,14 +1244,16 @@ TRACE_EVENT(drv_remain_on_channel,
LOCAL_ASSIGN; LOCAL_ASSIGN;
VIF_ASSIGN; VIF_ASSIGN;
__entry->center_freq = chan->center_freq; __entry->center_freq = chan->center_freq;
__entry->freq_offset = chan->freq_offset;
__entry->duration = duration; __entry->duration = duration;
__entry->type = type; __entry->type = type;
), ),
TP_printk( 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, 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 { struct trace_chandef_entry {
u32 control_freq; u32 control_freq;
u32 freq_offset;
u32 chan_width; u32 chan_width;
u32 center_freq1; u32 center_freq1;
u32 freq1_offset;
u32 center_freq2; u32 center_freq2;
} __packed; } __packed;
@@ -1597,18 +1614,26 @@ TRACE_EVENT(drv_switch_vif_chanctx,
sizeof(local_vifs[i].vif.vif_name)); sizeof(local_vifs[i].vif.vif_name));
SWITCH_ENTRY_ASSIGN(old_chandef.control_freq, SWITCH_ENTRY_ASSIGN(old_chandef.control_freq,
old_ctx->def.chan->center_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, SWITCH_ENTRY_ASSIGN(old_chandef.chan_width,
old_ctx->def.width); old_ctx->def.width);
SWITCH_ENTRY_ASSIGN(old_chandef.center_freq1, SWITCH_ENTRY_ASSIGN(old_chandef.center_freq1,
old_ctx->def.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, SWITCH_ENTRY_ASSIGN(old_chandef.center_freq2,
old_ctx->def.center_freq2); old_ctx->def.center_freq2);
SWITCH_ENTRY_ASSIGN(new_chandef.control_freq, SWITCH_ENTRY_ASSIGN(new_chandef.control_freq,
new_ctx->def.chan->center_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, SWITCH_ENTRY_ASSIGN(new_chandef.chan_width,
new_ctx->def.width); new_ctx->def.width);
SWITCH_ENTRY_ASSIGN(new_chandef.center_freq1, SWITCH_ENTRY_ASSIGN(new_chandef.center_freq1,
new_ctx->def.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, SWITCH_ENTRY_ASSIGN(new_chandef.center_freq2,
new_ctx->def.center_freq2); new_ctx->def.center_freq2);
} }

View File

@@ -4883,6 +4883,9 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
txrc.bss_conf = &sdata->vif.bss_conf; txrc.bss_conf = &sdata->vif.bss_conf;
txrc.skb = skb; txrc.skb = skb;
txrc.reported_rate.idx = -1; 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.rate_idx_mask = sdata->rc_rateidx_mask[band];
txrc.bss = true; txrc.bss = true;
rate_control_get_rate(sdata, NULL, &txrc); 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 = skb_put_zero(skb, sizeof(*pspoll));
pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
IEEE80211_STYPE_PSPOLL); 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 */ /* aid in PS-Poll has its two MSBs each set to 1 */
pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);

View File

@@ -4,7 +4,7 @@
* *
* Portions of this file * Portions of this file
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright (C) 2018 - 2019 Intel Corporation * Copyright (C) 2018 - 2020 Intel Corporation
*/ */
#include <linux/ieee80211.h> #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) { switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: 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; sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
break; break;
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 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; sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
break; break;
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 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; sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
break; break;
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
/* legacy only, no longer used by newer spec */
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
break; break;
} }

View File

@@ -27,6 +27,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
return; return;
chandef->chan = chan; chandef->chan = chan;
chandef->freq1_offset = chan->freq_offset;
chandef->center_freq2 = 0; chandef->center_freq2 = 0;
chandef->edmg.bw_config = 0; chandef->edmg.bw_config = 0;
chandef->edmg.channels = 0; chandef->edmg.channels = 0;
@@ -146,6 +147,9 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
if (!chandef->chan) if (!chandef->chan)
return false; return false;
if (chandef->freq1_offset >= 1000)
return false;
control_freq = chandef->chan->center_freq; control_freq = chandef->chan->center_freq;
switch (chandef->width) { 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_10:
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT: 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; return false;
if (chandef->center_freq2) if (chandef->center_freq2)
return false; return false;
@@ -386,10 +391,11 @@ static u32 cfg80211_get_start_freq(u32 center_freq,
{ {
u32 start_freq; u32 start_freq;
if (bandwidth <= 20) bandwidth = MHZ_TO_KHZ(bandwidth);
if (bandwidth <= MHZ_TO_KHZ(20))
start_freq = center_freq; start_freq = center_freq;
else else
start_freq = center_freq - bandwidth/2 + 10; start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
return start_freq; return start_freq;
} }
@@ -399,10 +405,11 @@ static u32 cfg80211_get_end_freq(u32 center_freq,
{ {
u32 end_freq; u32 end_freq;
if (bandwidth <= 20) bandwidth = MHZ_TO_KHZ(bandwidth);
if (bandwidth <= MHZ_TO_KHZ(20))
end_freq = center_freq; end_freq = center_freq;
else else
end_freq = center_freq + bandwidth/2 - 10; end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
return end_freq; 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); start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth); end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) { for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel_khz(wiphy, freq);
if (!c) if (!c)
return -EINVAL; return -EINVAL;
@@ -449,7 +456,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return -EINVAL; return -EINVAL;
ret = cfg80211_get_chans_dfs_required(wiphy, ret = cfg80211_get_chans_dfs_required(wiphy,
chandef->center_freq1, ieee80211_chandef_to_khz(chandef),
width); width);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -460,7 +467,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
return 0; return 0;
ret = cfg80211_get_chans_dfs_required(wiphy, ret = cfg80211_get_chans_dfs_required(wiphy,
chandef->center_freq2, MHZ_TO_KHZ(chandef->center_freq2),
width); width);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -503,8 +510,8 @@ static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
* DFS_AVAILABLE). Return number of usable channels * DFS_AVAILABLE). Return number of usable channels
* (require CAC). Allow DFS and non-DFS channel mix. * (require CAC). Allow DFS and non-DFS channel mix.
*/ */
for (freq = start_freq; freq <= end_freq; freq += 20) { for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel_khz(wiphy, freq);
if (!c) if (!c)
return -EINVAL; return -EINVAL;
@@ -536,7 +543,8 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
if (width < 0) if (width < 0)
return false; 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); width);
if (r1 < 0) if (r1 < 0)
@@ -546,7 +554,7 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2); WARN_ON(!chandef->center_freq2);
r2 = cfg80211_get_chans_dfs_usable(wiphy, r2 = cfg80211_get_chans_dfs_usable(wiphy,
chandef->center_freq2, MHZ_TO_KHZ(chandef->center_freq2),
width); width);
if (r2 < 0) if (r2 < 0)
return false; 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 * If any channel in between is disabled or has not
* had gone through CAC return false * had gone through CAC return false
*/ */
for (freq = start_freq; freq <= end_freq; freq += 20) { for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel_khz(wiphy, freq);
if (!c) if (!c)
return false; return false;
@@ -724,7 +732,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
if (width < 0) if (width < 0)
return false; 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); width);
/* If any of channels unavailable for cf1 just return */ /* 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: case NL80211_CHAN_WIDTH_80P80:
WARN_ON(!chandef->center_freq2); WARN_ON(!chandef->center_freq2);
r = cfg80211_get_chans_dfs_available(wiphy, r = cfg80211_get_chans_dfs_available(wiphy,
chandef->center_freq2, MHZ_TO_KHZ(chandef->center_freq2),
width); width);
break; break;
default: 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); start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth); end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) { for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel_khz(wiphy, freq);
if (!c) if (!c)
return 0; return 0;
@@ -790,14 +799,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
return 0; return 0;
t1 = cfg80211_get_chans_dfs_cac_time(wiphy, t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
chandef->center_freq1, MHZ_TO_KHZ(chandef->center_freq1),
width); width);
if (!chandef->center_freq2) if (!chandef->center_freq2)
return t1; return t1;
t2 = cfg80211_get_chans_dfs_cac_time(wiphy, t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
chandef->center_freq2, MHZ_TO_KHZ(chandef->center_freq2),
width); width);
return max(t1, t2); 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); start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth); end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) { for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel_khz(wiphy, freq);
if (!c || c->flags & prohibited_flags) if (!c || c->flags & prohibited_flags)
return false; return false;
} }
@@ -976,13 +985,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
prohibited_flags |= IEEE80211_CHAN_NO_OFDM; 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)) width, prohibited_flags))
return false; return false;
if (!chandef->center_freq2) if (!chandef->center_freq2)
return true; 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); width, prohibited_flags);
} }
EXPORT_SYMBOL(cfg80211_chandef_usable); EXPORT_SYMBOL(cfg80211_chandef_usable);

View File

@@ -480,9 +480,6 @@ use_default_name:
INIT_LIST_HEAD(&rdev->bss_list); INIT_LIST_HEAD(&rdev->bss_list);
INIT_LIST_HEAD(&rdev->sched_scan_req_list); INIT_LIST_HEAD(&rdev->sched_scan_req_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 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, INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
cfg80211_dfs_channels_update_work); cfg80211_dfs_channels_update_work);
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
@@ -837,6 +834,9 @@ int wiphy_register(struct wiphy *wiphy)
sband->channels[i].orig_mpwr = sband->channels[i].orig_mpwr =
sband->channels[i].max_power; sband->channels[i].max_power;
sband->channels[i].band = band; 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++) { 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); cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
flush_work(&rdev->destroy_work); flush_work(&rdev->destroy_work);
flush_work(&rdev->sched_scan_stop_wk); flush_work(&rdev->sched_scan_stop_wk);
flush_work(&rdev->mlme_unreg_wk);
flush_work(&rdev->propagate_radar_detect_wk); flush_work(&rdev->propagate_radar_detect_wk);
flush_work(&rdev->propagate_cac_done_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++; rdev->devlist_generation++;
cfg80211_mlme_purge_registrations(wdev); cfg80211_mlme_purge_registrations(wdev);
flush_work(&wdev->mgmt_registrations_update_wk);
switch (wdev->iftype) { switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_P2P_DEVICE:
@@ -1238,6 +1238,8 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev,
spin_lock_init(&wdev->event_lock); spin_lock_init(&wdev->event_lock);
INIT_LIST_HEAD(&wdev->mgmt_registrations); INIT_LIST_HEAD(&wdev->mgmt_registrations);
spin_lock_init(&wdev->mgmt_registrations_lock); 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); INIT_LIST_HEAD(&wdev->pmsr_list);
spin_lock_init(&wdev->pmsr_lock); spin_lock_init(&wdev->pmsr_lock);
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk); INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);

View File

@@ -60,10 +60,6 @@ struct cfg80211_registered_device {
struct list_head beacon_registrations; struct list_head beacon_registrations;
spinlock_t beacon_registrations_lock; 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 */ /* protected by RTNL only */
int num_running_ifaces; int num_running_ifaces;
int num_running_monitor_ifaces; int num_running_monitor_ifaces;
@@ -385,8 +381,9 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
struct net_device *dev); struct net_device *dev);
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
u16 frame_type, const u8 *match_data, u16 frame_type, const u8 *match_data,
int match_len, struct netlink_ext_ack *extack); int match_len, bool multicast_rx,
void cfg80211_mlme_unreg_wk(struct work_struct *wk); 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_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,

View File

@@ -426,58 +426,62 @@ struct cfg80211_mgmt_registration {
__le16 frame_type; __le16 frame_type;
bool multicast_rx;
u8 match[]; u8 match[];
}; };
static void static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev)
cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev)
{ {
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct wireless_dev *tmp;
struct cfg80211_mgmt_registration *reg; struct cfg80211_mgmt_registration *reg;
struct mgmt_frame_regs upd = {};
ASSERT_RTNL(); ASSERT_RTNL();
spin_lock_bh(&rdev->mlme_unreg_lock); rcu_read_lock();
while ((reg = list_first_entry_or_null(&rdev->mlme_unreg, list_for_each_entry_rcu(tmp, &rdev->wiphy.wdev_list, list) {
struct cfg80211_mgmt_registration, list_for_each_entry_rcu(reg, &tmp->mgmt_registrations, list) {
list))) { u32 mask = BIT(le16_to_cpu(reg->frame_type) >> 4);
list_del(&reg->list); u32 mcast_mask = 0;
spin_unlock_bh(&rdev->mlme_unreg_lock);
if (rdev->ops->mgmt_frame_register) { if (reg->multicast_rx)
u16 frame_type = le16_to_cpu(reg->frame_type); mcast_mask = mask;
rdev_mgmt_frame_register(rdev, reg->wdev, upd.global_stypes |= mask;
frame_type, false); 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); void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk)
spin_lock_bh(&rdev->mlme_unreg_lock);
}
spin_unlock_bh(&rdev->mlme_unreg_lock);
}
void cfg80211_mlme_unreg_wk(struct work_struct *wk)
{ {
struct cfg80211_registered_device *rdev; struct wireless_dev *wdev = container_of(wk, struct wireless_dev,
mgmt_registrations_update_wk);
rdev = container_of(wk, struct cfg80211_registered_device,
mlme_unreg_wk);
rtnl_lock(); rtnl_lock();
cfg80211_process_mlme_unregistrations(rdev); cfg80211_mgmt_registrations_update(wdev);
rtnl_unlock(); rtnl_unlock();
} }
int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
u16 frame_type, const u8 *match_data, 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; struct cfg80211_mgmt_registration *reg, *nreg;
int err = 0; int err = 0;
u16 mgmt_type; u16 mgmt_type;
bool update_multicast = false;
if (!wdev->wiphy->mgmt_stypes) if (!wdev->wiphy->mgmt_stypes)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@@ -528,34 +532,39 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
continue; continue;
if (memcmp(reg->match, match_data, mlen) == 0) { 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"); NL_SET_ERR_MSG(extack, "Match already configured");
err = -EALREADY; err = -EALREADY;
break; break;
} }
} }
if (err) { if (err)
kfree(nreg);
goto out; goto out;
}
if (update_multicast) {
kfree(nreg);
} else {
memcpy(nreg->match, match_data, match_len); memcpy(nreg->match, match_data, match_len);
nreg->match_len = match_len; nreg->match_len = match_len;
nreg->nlportid = snd_portid; nreg->nlportid = snd_portid;
nreg->frame_type = cpu_to_le16(frame_type); nreg->frame_type = cpu_to_le16(frame_type);
nreg->wdev = wdev; nreg->wdev = wdev;
nreg->multicast_rx = multicast_rx;
list_add(&nreg->list, &wdev->mgmt_registrations); list_add(&nreg->list, &wdev->mgmt_registrations);
}
spin_unlock_bh(&wdev->mgmt_registrations_lock); spin_unlock_bh(&wdev->mgmt_registrations_lock);
/* process all unregistrations to avoid driver confusion */ cfg80211_mgmt_registrations_update(wdev);
cfg80211_process_mlme_unregistrations(rdev);
if (rdev->ops->mgmt_frame_register)
rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
return 0; return 0;
out: out:
kfree(nreg);
spin_unlock_bh(&wdev->mgmt_registrations_lock); spin_unlock_bh(&wdev->mgmt_registrations_lock);
return err; return err;
@@ -574,11 +583,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
continue; continue;
list_del(&reg->list); list_del(&reg->list);
spin_lock(&rdev->mlme_unreg_lock); kfree(reg);
list_add_tail(&reg->list, &rdev->mlme_unreg);
spin_unlock(&rdev->mlme_unreg_lock);
schedule_work(&rdev->mlme_unreg_wk); schedule_work(&wdev->mgmt_registrations_update_wk);
} }
spin_unlock_bh(&wdev->mgmt_registrations_lock); 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) 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_bh(&wdev->mgmt_registrations_lock);
spin_lock(&rdev->mlme_unreg_lock); list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg); list_del(&reg->list);
spin_unlock(&rdev->mlme_unreg_lock); kfree(reg);
}
spin_unlock_bh(&wdev->mgmt_registrations_lock); 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, int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,

View File

@@ -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_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
[NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1), [NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
[NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100), [NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
[NL80211_ATTR_RECEIVE_MULTICAST] = { .type = NLA_FLAG },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
@@ -3860,15 +3861,26 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
}; };
void *hdr; void *hdr;
struct sk_buff *msg; 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]) { if (info->attrs[NL80211_ATTR_KEY_IDX]) {
key_idx = nla_get_u8(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( if (key_idx >= 6 && key_idx <= 7 && !bigtk_support) {
&rdev->wiphy, GENL_SET_ERR_MSG(info, "BIGTK not supported");
NL80211_EXT_FEATURE_BEACON_PROTECTION))
return -EINVAL; return -EINVAL;
} }
}
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(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; params->ht_required = true;
if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY) if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
params->vht_required = true; 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) if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP; 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, return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
info->attrs[NL80211_ATTR_RECEIVE_MULTICAST],
info->extack); info->extack);
} }
@@ -15495,10 +15518,19 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
if (WARN_ON(len < 2)) if (WARN_ON(len < 2))
return; return;
if (ieee80211_is_deauth(mgmt->frame_control)) if (ieee80211_is_deauth(mgmt->frame_control)) {
cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE; cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
else } else if (ieee80211_is_disassoc(mgmt->frame_control)) {
cmd = NL80211_CMD_UNPROT_DISASSOCIATE; 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); trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1, nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,

View File

@@ -819,13 +819,16 @@ rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
} }
static inline void static inline void
rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev, rdev_update_mgmt_frame_registrations(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u16 frame_type, bool reg) struct wireless_dev *wdev,
struct mgmt_frame_regs *upd)
{ {
might_sleep(); might_sleep();
trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); trace_rdev_update_mgmt_frame_registrations(&rdev->wiphy, wdev, upd);
rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); if (rdev->ops->update_mgmt_frame_registrations)
rdev->ops->update_mgmt_frame_registrations(&rdev->wiphy, wdev,
upd);
trace_rdev_return_void(&rdev->wiphy); trace_rdev_return_void(&rdev->wiphy);
} }

View File

@@ -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_channel *chan)
{ {
const struct ieee80211_freq_range *freq_range = NULL; 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 = &reg_rule->freq_range; freq_range = &reg_rule->freq_range;
max_bandwidth_khz = freq_range->max_bandwidth_khz; max_bandwidth_khz = freq_range->max_bandwidth_khz;
center_freq_khz = ieee80211_channel_to_khz(chan);
/* Check if auto calculation requested */ /* Check if auto calculation requested */
if (reg_rule->flags & NL80211_RRF_AUTO_BW) if (reg_rule->flags & NL80211_RRF_AUTO_BW)
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); 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 we get a reg_rule we can assume that at least 5Mhz fit */
if (!cfg80211_does_bw_fit_range(freq_range, if (!cfg80211_does_bw_fit_range(freq_range,
MHZ_TO_KHZ(chan->center_freq), center_freq_khz,
MHZ_TO_KHZ(10))) MHZ_TO_KHZ(10)))
bw_flags |= IEEE80211_CHAN_NO_10MHZ; bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (!cfg80211_does_bw_fit_range(freq_range, if (!cfg80211_does_bw_fit_range(freq_range,
MHZ_TO_KHZ(chan->center_freq), center_freq_khz,
MHZ_TO_KHZ(20))) MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ; bw_flags |= IEEE80211_CHAN_NO_20MHZ;
@@ -1710,7 +1711,7 @@ static void handle_channel(struct wiphy *wiphy,
flags = chan->orig_flags; 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)) { if (IS_ERR(reg_rule)) {
/* /*
* We will disable all channels that do not match our * 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 && if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
request_wiphy && request_wiphy == wiphy && request_wiphy && request_wiphy == wiphy &&
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
pr_debug("Disabling freq %d MHz for good\n", pr_debug("Disabling freq %d.%03d MHz for good\n",
chan->center_freq); chan->center_freq, chan->freq_offset);
chan->orig_flags |= IEEE80211_CHAN_DISABLED; chan->orig_flags |= IEEE80211_CHAN_DISABLED;
chan->flags = chan->orig_flags; chan->flags = chan->orig_flags;
} else { } else {
pr_debug("Disabling freq %d MHz\n", pr_debug("Disabling freq %d.%03d MHz\n",
chan->center_freq); chan->center_freq, chan->freq_offset);
chan->flags |= IEEE80211_CHAN_DISABLED; chan->flags |= IEEE80211_CHAN_DISABLED;
} }
return; return;
@@ -1936,7 +1937,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
sband = wiphy->bands[reg_beacon->chan.band]; sband = wiphy->bands[reg_beacon->chan.band];
chan = &sband->channels[chan_idx]; chan = &sband->channels[chan_idx];
if (likely(chan->center_freq != reg_beacon->chan.center_freq)) if (likely(!ieee80211_channel_equal(chan, &reg_beacon->chan)))
return; return;
if (chan->beacon_found) if (chan->beacon_found)
@@ -2269,18 +2270,18 @@ static void handle_channel_custom(struct wiphy *wiphy,
u32 bw_flags = 0; u32 bw_flags = 0;
const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_power_rule *power_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) { for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq), reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw);
regd, bw);
if (!IS_ERR(reg_rule)) if (!IS_ERR(reg_rule))
break; break;
} }
if (IS_ERR_OR_NULL(reg_rule)) { if (IS_ERR_OR_NULL(reg_rule)) {
pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n", pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n",
chan->center_freq); chan->center_freq, chan->freq_offset);
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
chan->flags |= IEEE80211_CHAN_DISABLED; chan->flags |= IEEE80211_CHAN_DISABLED;
} else { } else {
@@ -3337,8 +3338,8 @@ static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
struct reg_beacon *pending_beacon; struct reg_beacon *pending_beacon;
list_for_each_entry(pending_beacon, &reg_pending_beacons, list) list_for_each_entry(pending_beacon, &reg_pending_beacons, list)
if (beacon_chan->center_freq == if (ieee80211_channel_equal(beacon_chan,
pending_beacon->chan.center_freq) &pending_beacon->chan))
return true; return true;
return false; return false;
} }
@@ -3367,9 +3368,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
if (!reg_beacon) if (!reg_beacon)
return -ENOMEM; return -ENOMEM;
pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n", pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n",
beacon_chan->center_freq, beacon_chan->center_freq, beacon_chan->freq_offset,
ieee80211_frequency_to_channel(beacon_chan->center_freq), ieee80211_freq_khz_to_channel(
ieee80211_channel_to_khz(beacon_chan)),
wiphy_name(wiphy)); wiphy_name(wiphy));
memcpy(&reg_beacon->chan, beacon_chan, memcpy(&reg_beacon->chan, beacon_chan,

View File

@@ -1322,8 +1322,8 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
return channel; return channel;
} }
freq = ieee80211_channel_to_frequency(channel_number, channel->band); freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
alt_channel = ieee80211_get_channel(wiphy, freq); alt_channel = ieee80211_get_channel_khz(wiphy, freq);
if (!alt_channel) { if (!alt_channel) {
if (channel->band == NL80211_BAND_2GHZ) { if (channel->band == NL80211_BAND_2GHZ) {
/* /*

View File

@@ -694,6 +694,7 @@ void __cfg80211_connect_result(struct net_device *dev,
return; return;
} }
wdev->unprot_beacon_reported = 0;
nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr, nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
GFP_KERNEL); GFP_KERNEL);
@@ -921,6 +922,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
cfg80211_hold_bss(bss_from_pub(info->bss)); cfg80211_hold_bss(bss_from_pub(info->bss));
wdev->current_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), nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
wdev->netdev, info, GFP_KERNEL); wdev->netdev, info, GFP_KERNEL);

View File

@@ -112,24 +112,29 @@
} while (0) } while (0)
#define CHAN_ENTRY __field(enum nl80211_band, band) \ #define CHAN_ENTRY __field(enum nl80211_band, band) \
__field(u32, center_freq) __field(u32, center_freq) \
__field(u16, freq_offset)
#define CHAN_ASSIGN(chan) \ #define CHAN_ASSIGN(chan) \
do { \ do { \
if (chan) { \ if (chan) { \
__entry->band = chan->band; \ __entry->band = chan->band; \
__entry->center_freq = chan->center_freq; \ __entry->center_freq = chan->center_freq; \
__entry->freq_offset = chan->freq_offset; \
} else { \ } else { \
__entry->band = 0; \ __entry->band = 0; \
__entry->center_freq = 0; \ __entry->center_freq = 0; \
__entry->freq_offset = 0; \
} \ } \
} while (0) } while (0)
#define CHAN_PR_FMT "band: %d, freq: %u" #define CHAN_PR_FMT "band: %d, freq: %u.%03u"
#define CHAN_PR_ARG __entry->band, __entry->center_freq #define CHAN_PR_ARG __entry->band, __entry->center_freq, __entry->freq_offset
#define CHAN_DEF_ENTRY __field(enum nl80211_band, band) \ #define CHAN_DEF_ENTRY __field(enum nl80211_band, band) \
__field(u32, control_freq) \ __field(u32, control_freq) \
__field(u32, freq_offset) \
__field(u32, width) \ __field(u32, width) \
__field(u32, center_freq1) \ __field(u32, center_freq1) \
__field(u32, freq1_offset) \
__field(u32, center_freq2) __field(u32, center_freq2)
#define CHAN_DEF_ASSIGN(chandef) \ #define CHAN_DEF_ASSIGN(chandef) \
do { \ do { \
@@ -137,21 +142,27 @@
__entry->band = (chandef)->chan->band; \ __entry->band = (chandef)->chan->band; \
__entry->control_freq = \ __entry->control_freq = \
(chandef)->chan->center_freq; \ (chandef)->chan->center_freq; \
__entry->freq_offset = \
(chandef)->chan->freq_offset; \
__entry->width = (chandef)->width; \ __entry->width = (chandef)->width; \
__entry->center_freq1 = (chandef)->center_freq1;\ __entry->center_freq1 = (chandef)->center_freq1;\
__entry->freq1_offset = (chandef)->freq1_offset;\
__entry->center_freq2 = (chandef)->center_freq2;\ __entry->center_freq2 = (chandef)->center_freq2;\
} else { \ } else { \
__entry->band = 0; \ __entry->band = 0; \
__entry->control_freq = 0; \ __entry->control_freq = 0; \
__entry->freq_offset = 0; \
__entry->width = 0; \ __entry->width = 0; \
__entry->center_freq1 = 0; \ __entry->center_freq1 = 0; \
__entry->freq1_offset = 0; \
__entry->center_freq2 = 0; \ __entry->center_freq2 = 0; \
} \ } \
} while (0) } while (0)
#define CHAN_DEF_PR_FMT \ #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, \ #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 __entry->center_freq2
#define SINFO_ENTRY __field(int, generation) \ #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)) 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, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
u16 frame_type, bool reg), struct mgmt_frame_regs *upd),
TP_ARGS(wiphy, wdev, frame_type, reg), TP_ARGS(wiphy, wdev, upd),
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
WDEV_ENTRY WDEV_ENTRY
__field(u16, frame_type) __field(u16, global_stypes)
__field(bool, reg) __field(u16, interface_stypes)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
WDEV_ASSIGN; WDEV_ASSIGN;
__entry->frame_type = frame_type; __entry->global_stypes = upd->global_stypes;
__entry->reg = reg; __entry->interface_stypes = upd->interface_stypes;
), ),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ", TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", global: 0x%.2x, intf: 0x%.2x",
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type, WIPHY_PR_ARG, WDEV_PR_ARG,
__entry->reg ? "true" : "false") __entry->global_stypes, __entry->interface_stypes)
); );
TRACE_EVENT(rdev_return_int_tx_rx, TRACE_EVENT(rdev_return_int_tx_rx,

View File

@@ -5,7 +5,7 @@
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2017 Intel Deutschland GmbH * Copyright 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2019 Intel Corporation * Copyright (C) 2018-2020 Intel Corporation
*/ */
#include <linux/export.h> #include <linux/export.h>
#include <linux/bitops.h> #include <linux/bitops.h>
@@ -72,7 +72,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
} }
EXPORT_SYMBOL(ieee80211_mandatory_rates); 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 /* see 802.11 17.3.8.3.2 and Annex J
* there are overlapping channel numbers in 5GHz and 2GHz bands */ * 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) { switch (band) {
case NL80211_BAND_2GHZ: case NL80211_BAND_2GHZ:
if (chan == 14) if (chan == 14)
return 2484; return MHZ_TO_KHZ(2484);
else if (chan < 14) else if (chan < 14)
return 2407 + chan * 5; return MHZ_TO_KHZ(2407 + chan * 5);
break; break;
case NL80211_BAND_5GHZ: case NL80211_BAND_5GHZ:
if (chan >= 182 && chan <= 196) if (chan >= 182 && chan <= 196)
return 4000 + chan * 5; return MHZ_TO_KHZ(4000 + chan * 5);
else else
return 5000 + chan * 5; return MHZ_TO_KHZ(5000 + chan * 5);
break; break;
case NL80211_BAND_6GHZ: case NL80211_BAND_6GHZ:
/* see 802.11ax D4.1 27.3.22.2 */ /* 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; break;
case NL80211_BAND_60GHZ: case NL80211_BAND_60GHZ:
if (chan < 7) if (chan < 7)
return 56160 + chan * 2160; return MHZ_TO_KHZ(56160 + chan * 2160);
break; break;
default: default:
; ;
} }
return 0; /* not supported */ 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 */ /* see 802.11 17.3.8.3.2 and Annex J */
if (freq == 2484) if (freq == 2484)
return 14; return 14;
@@ -126,9 +129,10 @@ int ieee80211_frequency_to_channel(int freq)
else else
return 0; 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; enum nl80211_band band;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
@@ -141,14 +145,16 @@ struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
continue; continue;
for (i = 0; i < sband->n_channels; i++) { for (i = 0; i < sband->n_channels; i++) {
if (sband->channels[i].center_freq == freq) struct ieee80211_channel *chan = &sband->channels[i];
return &sband->channels[i];
if (ieee80211_channel_to_khz(chan) == freq)
return chan;
} }
} }
return NULL; return NULL;
} }
EXPORT_SYMBOL(ieee80211_get_channel); EXPORT_SYMBOL(ieee80211_get_channel_khz);
static void set_mandatory_flags_band(struct ieee80211_supported_band *sband) 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, int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
enum ieee80211_vht_chanwidth bw, 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); u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map);
int max_vht_nss = 0;
int ext_nss_bw; int ext_nss_bw;
int supp_width; int supp_width;
int i, mcs_encoding; int i, mcs_encoding;
@@ -2041,7 +2047,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
if (map == 0xffff) if (map == 0xffff)
return 0; return 0;
if (WARN_ON(mcs > 9)) if (WARN_ON(mcs > 9 || max_vht_nss > 8))
return 0; return 0;
if (mcs <= 7) if (mcs <= 7)
mcs_encoding = 0; mcs_encoding = 0;
@@ -2050,6 +2056,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
else else
mcs_encoding = 2; mcs_encoding = 2;
if (!max_vht_nss) {
/* find max_vht_nss for the given MCS */ /* find max_vht_nss for the given MCS */
for (i = 7; i >= 0; i--) { for (i = 7; i >= 0; i--) {
int supp = (map >> (2 * i)) & 3; int supp = (map >> (2 * i)) & 3;
@@ -2062,6 +2069,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
break; break;
} }
} }
}
if (!(cap->supp_mcs.tx_mcs_map & if (!(cap->supp_mcs.tx_mcs_map &
cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))