]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
Merge tag 'mac80211-next-for-net-next-2020-04-25' of git://git.kernel.org/pub/scm...
authorDavid S. Miller <davem@davemloft.net>
Wed, 27 May 2020 03:17:35 +0000 (20:17 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 27 May 2020 03:17:35 +0000 (20:17 -0700)
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>
49 files changed:
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/quantenna/qtnfmac/cfg80211.c
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
drivers/staging/wilc1000/cfg80211.c
drivers/staging/wilc1000/cfg80211.h
drivers/staging/wilc1000/netdev.c
drivers/staging/wilc1000/netdev.h
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/regulatory.h
include/uapi/linux/nl80211.h
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs_netdev.c
net/mac80211/he.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.h
net/mac80211/tdls.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/vht.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c

index 5ffe55801ca40c56a35c8e6d0026a87ebd709052..d9117ebf2809730d0ee938caf27e2b83e7ff5b23 100644 (file)
@@ -1178,8 +1178,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
               sizeof(arg->peer_he_cap_macinfo));
        memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
               sizeof(arg->peer_he_cap_phyinfo));
-       memcpy(&arg->peer_he_ops, &vif->bss_conf.he_operation,
-              sizeof(arg->peer_he_ops));
+       arg->peer_he_ops = vif->bss_conf.he_oper.params;
 
        /* the top most byte is used to indicate BSS color info */
        arg->peer_he_ops &= 0xffffff;
index 37cf602d8adf35d6928dce2de5af394c1534b80c..67f8f2aa7a5363de33f46a73cdd296eba1cd1235 100644 (file)
@@ -3249,22 +3249,19 @@ static int ath6kl_get_antenna(struct wiphy *wiphy,
        return 0;
 }
 
-static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
-                                      struct wireless_dev *wdev,
-                                      u16 frame_type, bool reg)
+static void ath6kl_update_mgmt_frame_registrations(struct wiphy *wiphy,
+                                                  struct wireless_dev *wdev,
+                                                  struct mgmt_frame_regs *upd)
 {
        struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
 
-       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
-                  __func__, frame_type, reg);
-       if (frame_type == IEEE80211_STYPE_PROBE_REQ) {
-               /*
-                * Note: This notification callback is not allowed to sleep, so
-                * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we
-                * hardcode target to report Probe Request frames all the time.
-                */
-               vif->probe_req_report = reg;
-       }
+       /*
+        * FIXME: send WMI_PROBE_REQ_REPORT_CMD here instead of hardcoding
+        *        the reporting in the target all the time, this callback
+        *        *is* allowed to sleep after all.
+        */
+       vif->probe_req_report =
+               upd->interface_stypes & BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
 }
 
 static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
@@ -3464,7 +3461,8 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .remain_on_channel = ath6kl_remain_on_channel,
        .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel,
        .mgmt_tx = ath6kl_mgmt_tx,
-       .mgmt_frame_register = ath6kl_mgmt_frame_register,
+       .update_mgmt_frame_registrations =
+               ath6kl_update_mgmt_frame_registrations,
        .get_antenna = ath6kl_get_antenna,
        .sched_scan_start = ath6kl_cfg80211_sscan_start,
        .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
index fbec6dd551d65653ee5af69973f47889eb8083d0..a757abd7a599991028b04e37d79152537ab95182 100644 (file)
@@ -5031,21 +5031,15 @@ brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
 }
 
 static void
-brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
-                                  struct wireless_dev *wdev,
-                                  u16 frame_type, bool reg)
+brcmf_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
+                                              struct wireless_dev *wdev,
+                                              struct mgmt_frame_regs *upd)
 {
        struct brcmf_cfg80211_vif *vif;
-       u16 mgmt_type;
 
-       brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
-
-       mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
        vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
-       if (reg)
-               vif->mgmt_rx_reg |= BIT(mgmt_type);
-       else
-               vif->mgmt_rx_reg &= ~BIT(mgmt_type);
+
+       vif->mgmt_rx_reg = upd->interface_stypes;
 }
 
 
@@ -5460,7 +5454,8 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
        .change_station = brcmf_cfg80211_change_station,
        .sched_scan_start = brcmf_cfg80211_sched_scan_start,
        .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
-       .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
+       .update_mgmt_frame_registrations =
+               brcmf_cfg80211_update_mgmt_frame_registrations,
        .mgmt_tx = brcmf_cfg80211_mgmt_tx,
        .remain_on_channel = brcmf_p2p_remain_on_channel,
        .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
index 246265904b98af3422ddc0124f4074699a2753a7..a7264b282d798060641cf6fab2314f53feb69c68 100644 (file)
@@ -1,10 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014, 2018 - 2020 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
  *
  * Contact Information:
  *  Intel Linux Wireless <linuxwifi@intel.com>
@@ -1430,7 +1429,8 @@ static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
                 */
                if (ieee80211_get_vht_max_nss(&vht_cap,
                                              IEEE80211_VHT_CHANWIDTH_160MHZ,
-                                             0, true) < sta->rx_nss)
+                                             0, true,
+                                             sta->rx_nss) < sta->rx_nss)
                        return RATE_MCS_CHAN_WIDTH_80;
                return RATE_MCS_CHAN_WIDTH_160;
        case IEEE80211_STA_RX_BW_80:
index 0528d4cb4d37478bbed6008b20dde478e5390f87..f4ded2f2ee3b66b2bba8e923ca91d19ebd411937 100644 (file)
@@ -1068,6 +1068,47 @@ static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
        return res;
 }
 
+static void mac80211_hwsim_config_mac_nl(struct ieee80211_hw *hw,
+                                        const u8 *addr, bool add)
+{
+       struct mac80211_hwsim_data *data = hw->priv;
+       u32 _portid = READ_ONCE(data->wmediumd);
+       struct sk_buff *skb;
+       void *msg_head;
+
+       if (!_portid && !hwsim_virtio_enabled)
+               return;
+
+       skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
+                              add ? HWSIM_CMD_ADD_MAC_ADDR :
+                                    HWSIM_CMD_DEL_MAC_ADDR);
+       if (!msg_head) {
+               pr_debug("mac80211_hwsim: problem with msg_head\n");
+               goto nla_put_failure;
+       }
+
+       if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
+                   ETH_ALEN, data->addresses[1].addr))
+               goto nla_put_failure;
+
+       if (nla_put(skb, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN, addr))
+               goto nla_put_failure;
+
+       genlmsg_end(skb, msg_head);
+
+       if (hwsim_virtio_enabled)
+               hwsim_tx_virtio(data, skb);
+       else
+               hwsim_unicast_netgroup(data, skb, _portid);
+       return;
+nla_put_failure:
+       nlmsg_free(skb);
+}
+
 static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate)
 {
        u16 result = 0;
@@ -1545,6 +1586,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
                  vif->addr);
        hwsim_set_magic(vif);
 
+       if (vif->type != NL80211_IFTYPE_MONITOR)
+               mac80211_hwsim_config_mac_nl(hw, vif->addr, true);
+
        vif->cab_queue = 0;
        vif->hw_queue[IEEE80211_AC_VO] = 0;
        vif->hw_queue[IEEE80211_AC_VI] = 1;
@@ -1584,6 +1628,8 @@ static void mac80211_hwsim_remove_interface(
                  vif->addr);
        hwsim_check_magic(vif);
        hwsim_clear_magic(vif);
+       if (vif->type != NL80211_IFTYPE_MONITOR)
+               mac80211_hwsim_config_mac_nl(hw, vif->addr, false);
 }
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1781,6 +1827,8 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
        data->rx_filter = 0;
        if (*total_flags & FIF_ALLMULTI)
                data->rx_filter |= FIF_ALLMULTI;
+       if (*total_flags & FIF_MCAST_ACTION)
+               data->rx_filter |= FIF_MCAST_ACTION;
 
        *total_flags = data->rx_filter;
 }
@@ -2104,6 +2152,8 @@ static void hw_scan_work(struct work_struct *work)
                hwsim->hw_scan_vif = NULL;
                hwsim->tmp_chan = NULL;
                mutex_unlock(&hwsim->mutex);
+               mac80211_hwsim_config_mac_nl(hwsim->hw, hwsim->scan_addr,
+                                            false);
                return;
        }
 
@@ -2177,6 +2227,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
        memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
        mutex_unlock(&hwsim->mutex);
 
+       mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true);
        wiphy_dbg(hw->wiphy, "hwsim hw_scan request\n");
 
        ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0);
@@ -2220,6 +2271,7 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw,
        pr_debug("hwsim sw_scan request, prepping stuff\n");
 
        memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN);
+       mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, true);
        hwsim->scanning = true;
        memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
 
@@ -2236,6 +2288,7 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw,
 
        pr_debug("hwsim sw_scan_complete\n");
        hwsim->scanning = false;
+       mac80211_hwsim_config_mac_nl(hw, hwsim->scan_addr, false);
        eth_zero_addr(hwsim->scan_addr);
 
        mutex_unlock(&hwsim->mutex);
@@ -2413,6 +2466,11 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
        WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
 }
 
+static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       return 1;
+}
+
 #define HWSIM_COMMON_OPS                                       \
        .tx = mac80211_hwsim_tx,                                \
        .start = mac80211_hwsim_start,                          \
@@ -2423,6 +2481,7 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
        .config = mac80211_hwsim_config,                        \
        .configure_filter = mac80211_hwsim_configure_filter,    \
        .bss_info_changed = mac80211_hwsim_bss_info_changed,    \
+       .tx_last_beacon = mac80211_hwsim_tx_last_beacon,        \
        .sta_add = mac80211_hwsim_sta_add,                      \
        .sta_remove = mac80211_hwsim_sta_remove,                \
        .sta_notify = mac80211_hwsim_sta_notify,                \
@@ -3003,6 +3062,10 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                               NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
        wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
        wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
+       wiphy_ext_feature_set(hw->wiphy,
+                             NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
+       wiphy_ext_feature_set(hw->wiphy,
+                             NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
 
        hw->wiphy->interface_modes = param->iftypes;
 
index 28ade92adcb4439b2ae2e8dc939a74ed96c3a877..9dceed77c5d6863bfa7df962bf2a04b6955dfa7b 100644 (file)
@@ -75,6 +75,12 @@ enum hwsim_tx_control_flags {
  * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
  *     %HWSIM_ATTR_RADIO_ID
+ * @HWSIM_CMD_ADD_MAC_ADDR: add a receive MAC address (given in the
+ *     %HWSIM_ATTR_ADDR_RECEIVER attribute) to a device identified by
+ *     %HWSIM_ATTR_ADDR_TRANSMITTER. This lets wmediumd forward frames
+ *     to this receiver address for a given station.
+ * @HWSIM_CMD_DEL_MAC_ADDR: remove the MAC address again, the attributes
+ *     are the same as to @HWSIM_CMD_ADD_MAC_ADDR.
  * @__HWSIM_CMD_MAX: enum limit
  */
 enum {
@@ -85,6 +91,8 @@ enum {
        HWSIM_CMD_NEW_RADIO,
        HWSIM_CMD_DEL_RADIO,
        HWSIM_CMD_GET_RADIO,
+       HWSIM_CMD_ADD_MAC_ADDR,
+       HWSIM_CMD_DEL_MAC_ADDR,
        __HWSIM_CMD_MAX,
 };
 #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
index 12bfd653a4052d86c8d4e5c954405cb422e35f78..97813ac291aed6a6f791aa3f530d10cd1a333a0a 100644 (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.
  */
 static void
-mwifiex_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
-                                    struct wireless_dev *wdev,
-                                    u16 frame_type, bool reg)
+mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
+                                                struct wireless_dev *wdev,
+                                                struct mgmt_frame_regs *upd)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
-       u32 mask;
-
-       if (reg)
-               mask = priv->mgmt_frame_mask | BIT(frame_type >> 4);
-       else
-               mask = priv->mgmt_frame_mask & ~BIT(frame_type >> 4);
+       u32 mask = upd->interface_stypes;
 
        if (mask != priv->mgmt_frame_mask) {
                priv->mgmt_frame_mask = mask;
@@ -4187,7 +4182,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .del_key = mwifiex_cfg80211_del_key,
        .set_default_mgmt_key = mwifiex_cfg80211_set_default_mgmt_key,
        .mgmt_tx = mwifiex_cfg80211_mgmt_tx,
-       .mgmt_frame_register = mwifiex_cfg80211_mgmt_frame_register,
+       .update_mgmt_frame_registrations =
+               mwifiex_cfg80211_update_mgmt_frame_registrations,
        .remain_on_channel = mwifiex_cfg80211_remain_on_channel,
        .cancel_remain_on_channel = mwifiex_cfg80211_cancel_remain_on_channel,
        .set_default_key = mwifiex_cfg80211_set_default_key,
index 8be17106008dc9abbaee95a32b13b13514662158..54cdf3ad09d751737579acab8f62d5fb9d1206c2 100644 (file)
@@ -389,55 +389,57 @@ static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 }
 
 static void
-qtnf_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
-                        u16 frame_type, bool reg)
+qtnf_update_mgmt_frame_registrations(struct wiphy *wiphy,
+                                    struct wireless_dev *wdev,
+                                    struct mgmt_frame_regs *upd)
 {
        struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev);
-       u16 mgmt_type;
-       u16 new_mask;
-       u16 qlink_frame_type = 0;
+       u16 new_mask = upd->interface_stypes;
+       u16 old_mask = vif->mgmt_frames_bitmask;
+       static const struct {
+               u16 mask, qlink_type;
+       } updates[] = {
+               {
+                       .mask = BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                               BIT(IEEE80211_STYPE_ASSOC_REQ >> 4),
+                       .qlink_type = QLINK_MGMT_FRAME_ASSOC_REQ,
+               },
+               {
+                       .mask = BIT(IEEE80211_STYPE_AUTH >> 4),
+                       .qlink_type = QLINK_MGMT_FRAME_AUTH,
+               },
+               {
+                       .mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
+                       .qlink_type = QLINK_MGMT_FRAME_PROBE_REQ,
+               },
+               {
+                       .mask = BIT(IEEE80211_STYPE_ACTION >> 4),
+                       .qlink_type = QLINK_MGMT_FRAME_ACTION,
+               },
+       };
+       unsigned int i;
 
-       mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+       if (new_mask == old_mask)
+               return;
 
-       if (reg)
-               new_mask = vif->mgmt_frames_bitmask | BIT(mgmt_type);
-       else
-               new_mask = vif->mgmt_frames_bitmask & ~BIT(mgmt_type);
+       for (i = 0; i < ARRAY_SIZE(updates); i++) {
+               u16 mask = updates[i].mask;
+               u16 qlink_frame_type = updates[i].qlink_type;
+               bool reg;
 
-       if (new_mask == vif->mgmt_frames_bitmask)
-               return;
+               /* the ! are here due to the assoc/reassoc merge */
+               if (!(new_mask & mask) == !(old_mask & mask))
+                       continue;
 
-       switch (frame_type & IEEE80211_FCTL_STYPE) {
-       case IEEE80211_STYPE_REASSOC_REQ:
-       case IEEE80211_STYPE_ASSOC_REQ:
-               qlink_frame_type = QLINK_MGMT_FRAME_ASSOC_REQ;
-               break;
-       case IEEE80211_STYPE_AUTH:
-               qlink_frame_type = QLINK_MGMT_FRAME_AUTH;
-               break;
-       case IEEE80211_STYPE_PROBE_REQ:
-               qlink_frame_type = QLINK_MGMT_FRAME_PROBE_REQ;
-               break;
-       case IEEE80211_STYPE_ACTION:
-               qlink_frame_type = QLINK_MGMT_FRAME_ACTION;
-               break;
-       default:
-               pr_warn("VIF%u.%u: unsupported frame type: %X\n",
-                       vif->mac->macid, vif->vifid,
-                       (frame_type & IEEE80211_FCTL_STYPE) >> 4);
-               return;
-       }
+               reg = new_mask & mask;
 
-       if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg)) {
-               pr_warn("VIF%u.%u: failed to %sregister mgmt frame type 0x%x\n",
-                       vif->mac->macid, vif->vifid, reg ? "" : "un",
-                       frame_type);
-               return;
+               if (qtnf_cmd_send_register_mgmt(vif, qlink_frame_type, reg))
+                       pr_warn("VIF%u.%u: failed to %sregister qlink frame type 0x%x\n",
+                               vif->mac->macid, vif->vifid, reg ? "" : "un",
+                               qlink_frame_type);
        }
 
        vif->mgmt_frames_bitmask = new_mask;
-       pr_debug("VIF%u.%u: %sregistered mgmt frame type 0x%x\n",
-                vif->mac->macid, vif->vifid, reg ? "" : "un", frame_type);
 }
 
 static int
@@ -1017,7 +1019,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = {
        .change_beacon          = qtnf_change_beacon,
        .stop_ap                = qtnf_stop_ap,
        .set_wiphy_params       = qtnf_set_wiphy_params,
-       .mgmt_frame_register    = qtnf_mgmt_frame_register,
+       .update_mgmt_frame_registrations =
+               qtnf_update_mgmt_frame_registrations,
        .mgmt_tx                = qtnf_mgmt_tx,
        .change_station         = qtnf_change_station,
        .del_station            = qtnf_del_station,
index 1ba85a43f05aad6311cf733f1753c146cd24aa6a..cd31ad2b8a7b74f7d95344f83024ad0f13559f8e 100644 (file)
@@ -3163,29 +3163,6 @@ exit:
        return ret;
 }
 
-static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy,
-       struct wireless_dev *wdev,
-       u16 frame_type, bool reg)
-{
-       struct net_device *ndev = wdev_to_ndev(wdev);
-       struct adapter *adapter;
-
-       if (ndev == NULL)
-               goto exit;
-
-       adapter = (struct adapter *)rtw_netdev_priv(ndev);
-
-#ifdef DEBUG_CFG80211
-       DBG_871X(FUNC_ADPT_FMT" frame_type:%x, reg:%d\n", FUNC_ADPT_ARG(adapter),
-               frame_type, reg);
-#endif
-
-       if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
-               return;
-exit:
-       return;
-}
-
 #if defined(CONFIG_PNO_SUPPORT)
 static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy,
                struct net_device *dev,
@@ -3397,7 +3374,6 @@ static struct cfg80211_ops rtw_cfg80211_ops = {
        .change_bss = cfg80211_rtw_change_bss,
 
        .mgmt_tx = cfg80211_rtw_mgmt_tx,
-       .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register,
 
 #if defined(CONFIG_PNO_SUPPORT)
        .sched_scan_start = cfg80211_rtw_sched_scan_start,
index 4bdcbc5fd2fdd83155109df65a100d31b2478c76..b6065a0d660f80f6c4a1da182fd998c069d9f7d7 100644 (file)
@@ -1217,33 +1217,31 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy,
        return 0;
 }
 
-void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
-                             u16 frame_type, bool reg)
+void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         struct mgmt_frame_regs *upd)
 {
        struct wilc *wl = wiphy_priv(wiphy);
        struct wilc_vif *vif = netdev_priv(wdev->netdev);
+       u32 presp_bit = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
+       u32 action_bit = BIT(IEEE80211_STYPE_ACTION >> 4);
 
-       if (!frame_type)
-               return;
+       if (wl->initialized) {
+               bool prev = vif->mgmt_reg_stypes & presp_bit;
+               bool now = upd->interface_stypes & presp_bit;
 
-       switch (frame_type) {
-       case IEEE80211_STYPE_PROBE_REQ:
-               vif->frame_reg[0].type = frame_type;
-               vif->frame_reg[0].reg = reg;
-               break;
+               if (now != prev)
+                       wilc_frame_register(vif, IEEE80211_STYPE_PROBE_REQ, now);
 
-       case IEEE80211_STYPE_ACTION:
-               vif->frame_reg[1].type = frame_type;
-               vif->frame_reg[1].reg = reg;
-               break;
+               prev = vif->mgmt_reg_stypes & action_bit;
+               now = upd->interface_stypes & action_bit;
 
-       default:
-               break;
+               if (now != prev)
+                       wilc_frame_register(vif, IEEE80211_STYPE_ACTION, now);
        }
 
-       if (!wl->initialized)
-               return;
-       wilc_frame_register(vif, frame_type, reg);
+       vif->mgmt_reg_stypes =
+               upd->interface_stypes & (presp_bit | action_bit);
 }
 
 static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
@@ -1665,7 +1663,7 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
        .cancel_remain_on_channel = cancel_remain_on_channel,
        .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait,
        .mgmt_tx = mgmt_tx,
-       .mgmt_frame_register = wilc_mgmt_frame_register,
+       .update_mgmt_frame_registrations = wilc_update_mgmt_frame_registrations,
        .set_power_mgmt = set_power_mgmt,
        .set_cqm_rssi_config = set_cqm_rssi_config,
 
index 5e5d63f70df281a88770d530d27adca00cb24805..37b294cb3b3724d62d08be2c95a9996e103dd656 100644 (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,
                                               const char *name,
                                               struct net_device *real_dev);
-void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
-                             u16 frame_type, bool reg);
+void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         struct mgmt_frame_regs *upd);
 struct wilc_vif *wilc_get_interface(struct wilc *wl);
 struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl);
 void wlan_deinit_locks(struct wilc *wilc);
index f94a17babd12a651031a7f1185f3f2896f96668f..fda0ab97b02c2dbeb9e70803d36301bd722e4bec 100644 (file)
@@ -571,6 +571,7 @@ static int wilc_mac_open(struct net_device *ndev)
        struct wilc *wl = vif->wilc;
        unsigned char mac_add[ETH_ALEN] = {0};
        int ret = 0;
+       struct mgmt_frame_regs mgmt_regs = {};
 
        if (!wl || !wl->dev) {
                netdev_err(ndev, "device not ready\n");
@@ -602,14 +603,12 @@ static int wilc_mac_open(struct net_device *ndev)
                return -EINVAL;
        }
 
-       wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
-                                vif->ndev->ieee80211_ptr,
-                                vif->frame_reg[0].type,
-                                vif->frame_reg[0].reg);
-       wilc_mgmt_frame_register(vif->ndev->ieee80211_ptr->wiphy,
-                                vif->ndev->ieee80211_ptr,
-                                vif->frame_reg[1].type,
-                                vif->frame_reg[1].reg);
+       mgmt_regs.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,
+                                            &mgmt_regs);
        netif_wake_queue(ndev);
        wl->open_ifcs++;
        vif->mac_opened = 1;
@@ -792,12 +791,10 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
        srcu_idx = srcu_read_lock(&wilc->srcu);
        list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
                u16 type = le16_to_cpup((__le16 *)buff);
+               u32 type_bit = BIT(type >> 4);
 
                if (vif->priv.p2p_listen_state &&
-                   ((type == vif->frame_reg[0].type &&
-                     vif->frame_reg[0].reg) ||
-                    (type == vif->frame_reg[1].type &&
-                     vif->frame_reg[1].reg)))
+                   vif->mgmt_reg_stypes & type_bit)
                        wilc_wfi_p2p_rx(vif, buff, size);
 
                if (vif->monitor_flag)
index 61cbec674a626c6bfb0a20cbf23f6f18cf7ecb90..d0a006b68d08837cebd5de835019c03394473cad 100644 (file)
@@ -24,8 +24,6 @@
 #define PMKID_FOUND                            1
 #define NUM_STA_ASSOCIATED                     8
 
-#define NUM_REG_FRAME                          2
-
 #define TCP_ACK_FILTER_LINK_SPEED_THRESH       54
 #define DEFAULT_LINK_SPEED                     72
 
@@ -151,11 +149,6 @@ struct wilc_priv {
        u64 inc_roc_cookie;
 };
 
-struct frame_reg {
-       u16 type;
-       bool reg;
-};
-
 #define MAX_TCP_SESSION                25
 #define MAX_PENDING_ACKS               256
 
@@ -187,7 +180,7 @@ struct wilc_vif {
        u8 iftype;
        int monitor_flag;
        int mac_opened;
-       struct frame_reg frame_reg[NUM_REG_FRAME];
+       u32 mgmt_reg_stypes;
        struct net_device_stats netstats;
        struct wilc *wilc;
        u8 bssid[ETH_ALEN];
index 16268ef1cbccc4a4355062eeed0b329a94a0c8d8..a561db435a4b681b17b7fb1021c6c345a200e006 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
  * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH
  * Copyright (c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright (c) 2018 - 2019 Intel Corporation
+ * Copyright (c) 2018 - 2020 Intel Corporation
  */
 
 #ifndef LINUX_IEEE80211_H
@@ -859,6 +859,7 @@ enum ieee80211_ht_chanwidth_values {
  * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: 40 MHz channel width
  * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: 80 MHz channel width
  * @IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width
+ * @IEEE80211_OPMODE_NOTIF_BW_160_80P80: 160 / 80+80 MHz indicator flag
  * @IEEE80211_OPMODE_NOTIF_RX_NSS_MASK: number of spatial streams mask
  *     (the NSS value is the value of this field + 1)
  * @IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT: number of spatial streams shift
@@ -866,11 +867,12 @@ enum ieee80211_ht_chanwidth_values {
  *     using a beamforming steering matrix
  */
 enum ieee80211_vht_opmode_bits {
-       IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK   = 3,
+       IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK   = 0x03,
        IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ  = 0,
        IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ  = 1,
        IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ  = 2,
        IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ = 3,
+       IEEE80211_OPMODE_NOTIF_BW_160_80P80     = 0x04,
        IEEE80211_OPMODE_NOTIF_RX_NSS_MASK      = 0x70,
        IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT     = 4,
        IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF   = 0x80,
@@ -1065,6 +1067,7 @@ struct ieee80211_mgmt {
 /* Supported rates membership selectors */
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY        126
+#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122
 
 /* mgmt header + 1 byte category code */
 #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
@@ -1731,6 +1734,9 @@ struct ieee80211_mu_edca_param_set {
  * @ext_nss_bw_capable: indicates whether or not the local transmitter
  *     (rate scaling algorithm) can deal with the new logic
  *     (dot11VHTExtendedNSSBWCapable)
+ * @max_vht_nss: current maximum NSS as advertised by the STA in
+ *     operating mode notification, can be 0 in which case the
+ *     capability data will be used to derive this (from MCS support)
  *
  * Due to the VHT Extended NSS Bandwidth Support, the maximum NSS can
  * vary for a given BW/MCS. This function parses the data.
@@ -1739,7 +1745,8 @@ struct ieee80211_mu_edca_param_set {
  */
 int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
                              enum ieee80211_vht_chanwidth bw,
-                             int mcs, bool ext_nss_bw_capable);
+                             int mcs, bool ext_nss_bw_capable,
+                             unsigned int max_vht_nss);
 
 /* 802.11ax HE MAC capabilities */
 #define IEEE80211_HE_MAC_CAP0_HTC_HE                           0x01
@@ -3323,6 +3330,16 @@ static inline int ieee80211_get_tdls_action(struct sk_buff *skb, u32 hdr_size)
 #define TU_TO_JIFFIES(x)       (usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)      (jiffies + TU_TO_JIFFIES(x))
 
+/* convert frequencies */
+#define MHZ_TO_KHZ(freq) ((freq) * 1000)
+#define KHZ_TO_MHZ(freq) ((freq) / 1000)
+
+/* convert powers */
+#define DBI_TO_MBI(gain) ((gain) * 100)
+#define MBI_TO_DBI(gain) ((gain) / 100)
+#define DBM_TO_MBM(gain) ((gain) * 100)
+#define MBM_TO_DBM(gain) ((gain) / 100)
+
 /**
  * ieee80211_action_contains_tpc - checks if the frame contains TPC element
  * @skb: the skb containing the frame, length will be checked
index 46ac80423b2833e57b7b032b58fd316fe66ab57e..8b6d5c5184d169bc53a3c95c92df437082c2ea56 100644 (file)
@@ -128,6 +128,7 @@ enum ieee80211_channel_flags {
  * with cfg80211.
  *
  * @center_freq: center frequency in MHz
+ * @freq_offset: offset from @center_freq, in KHz
  * @hw_value: hardware-specific value for the channel
  * @flags: channel flags from &enum ieee80211_channel_flags.
  * @orig_flags: channel flags at registration time, used by regulatory
@@ -149,6 +150,7 @@ enum ieee80211_channel_flags {
 struct ieee80211_channel {
        enum nl80211_band band;
        u32 center_freq;
+       u16 freq_offset;
        u16 hw_value;
        u32 flags;
        int max_antenna_gain;
@@ -617,6 +619,7 @@ struct key_params {
  *     If edmg is requested (i.e. the .channels member is non-zero),
  *     chan will define the primary channel and all other
  *     parameters are ignored.
+ * @freq1_offset: offset from @center_freq1, in KHz
  */
 struct cfg80211_chan_def {
        struct ieee80211_channel *chan;
@@ -624,6 +627,7 @@ struct cfg80211_chan_def {
        u32 center_freq1;
        u32 center_freq2;
        struct ieee80211_edmg edmg;
+       u16 freq1_offset;
 };
 
 /**
@@ -713,6 +717,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
        return (chandef1->chan == chandef2->chan &&
                chandef1->width == chandef2->width &&
                chandef1->center_freq1 == chandef2->center_freq1 &&
+               chandef1->freq1_offset == chandef2->freq1_offset &&
                chandef1->center_freq2 == chandef2->center_freq2);
 }
 
@@ -1054,6 +1059,7 @@ enum cfg80211_ap_settings_flags {
  * @ht_required: stations must support HT
  * @vht_required: stations must support VHT
  * @twt_responder: Enable Target Wait Time
+ * @he_required: stations must support HE
  * @flags: flags, as defined in enum cfg80211_ap_settings_flags
  * @he_obss_pd: OBSS Packet Detection settings
  * @he_bss_color: BSS Color settings
@@ -1083,7 +1089,7 @@ struct cfg80211_ap_settings {
        const struct ieee80211_vht_cap *vht_cap;
        const struct ieee80211_he_cap_elem *he_cap;
        const struct ieee80211_he_operation *he_oper;
-       bool ht_required, vht_required;
+       bool ht_required, vht_required, he_required;
        bool twt_responder;
        u32 flags;
        struct ieee80211_he_obss_pd he_obss_pd;
@@ -3384,6 +3390,21 @@ struct cfg80211_update_owe_info {
        size_t ie_len;
 };
 
+/**
+ * struct mgmt_frame_regs - management frame registrations data
+ * @global_stypes: bitmap of management frame subtypes registered
+ *     for the entire device
+ * @interface_stypes: bitmap of management frame subtypes registered
+ *     for the given interface
+ * @global_mcast_rx: mcast RX is needed globally for these subtypes
+ * @interface_mcast_stypes: mcast RX is needed on this interface
+ *     for these subtypes
+ */
+struct mgmt_frame_regs {
+       u32 global_stypes, interface_stypes;
+       u32 global_mcast_stypes, interface_mcast_stypes;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -3608,8 +3629,8 @@ struct cfg80211_update_owe_info {
  *     The driver should not call cfg80211_sched_scan_stopped() for a requested
  *     stop (when this method returns 0).
  *
- * @mgmt_frame_register: Notify driver that a management frame type was
- *     registered. The callback is allowed to sleep.
+ * @update_mgmt_frame_registrations: Notify the driver that management frame
+ *     registrations were updated. The callback is allowed to sleep.
  *
  * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
  *     Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
@@ -3932,9 +3953,9 @@ struct cfg80211_ops {
                                      struct net_device *dev,
                                      u32 rate, u32 pkts, u32 intvl);
 
-       void    (*mgmt_frame_register)(struct wiphy *wiphy,
-                                      struct wireless_dev *wdev,
-                                      u16 frame_type, bool reg);
+       void    (*update_mgmt_frame_registrations)(struct wiphy *wiphy,
+                                                  struct wireless_dev *wdev,
+                                                  struct mgmt_frame_regs *upd);
 
        int     (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
        int     (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
@@ -5015,6 +5036,7 @@ struct cfg80211_cqm_config;
  *     by cfg80211 on change_interface
  * @mgmt_registrations: list of registrations for management frames
  * @mgmt_registrations_lock: lock for the list
+ * @mgmt_registrations_update_wk: update work to defer from atomic context
  * @mtx: mutex used to lock data in this struct, may be used by drivers
  *     and some API functions require it held
  * @beacon_interval: beacon interval used on this device for transmitting
@@ -5045,6 +5067,8 @@ struct cfg80211_cqm_config;
  * @pmsr_list: (private) peer measurement requests
  * @pmsr_lock: (private) peer measurements requests/results lock
  * @pmsr_free_wk: (private) peer measurements cleanup work
+ * @unprot_beacon_reported: (private) timestamp of last
+ *     unprotected beacon report
  */
 struct wireless_dev {
        struct wiphy *wiphy;
@@ -5058,6 +5082,7 @@ struct wireless_dev {
 
        struct list_head mgmt_registrations;
        spinlock_t mgmt_registrations_lock;
+       struct work_struct mgmt_registrations_update_wk;
 
        struct mutex mtx;
 
@@ -5121,6 +5146,8 @@ struct wireless_dev {
        struct list_head pmsr_list;
        spinlock_t pmsr_lock;
        struct work_struct pmsr_free_wk;
+
+       unsigned long unprot_beacon_reported;
 };
 
 static inline u8 *wdev_address(struct wireless_dev *wdev)
@@ -5155,30 +5182,92 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
  * cfg80211 offers a number of utility functions that can be useful.
  */
 
+/**
+ * ieee80211_channel_equal - compare two struct ieee80211_channel
+ *
+ * @a: 1st struct ieee80211_channel
+ * @b: 2nd struct ieee80211_channel
+ * Return: true if center frequency of @a == @b
+ */
+static inline bool
+ieee80211_channel_equal(struct ieee80211_channel *a,
+                       struct ieee80211_channel *b)
+{
+       return (a->center_freq == b->center_freq &&
+               a->freq_offset == b->freq_offset);
+}
+
+/**
+ * ieee80211_channel_to_khz - convert ieee80211_channel to frequency in KHz
+ * @chan: struct ieee80211_channel to convert
+ * Return: The corresponding frequency (in KHz)
+ */
+static inline u32
+ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
+{
+       return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
+}
+
+/**
+ * ieee80211_channel_to_freq_khz - convert channel number to frequency
+ * @chan: channel number
+ * @band: band, necessary due to channel number overlap
+ * Return: The corresponding frequency (in KHz), or 0 if the conversion failed.
+ */
+u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band);
+
 /**
  * ieee80211_channel_to_frequency - convert channel number to frequency
  * @chan: channel number
  * @band: band, necessary due to channel number overlap
  * Return: The corresponding frequency (in MHz), or 0 if the conversion failed.
  */
-int ieee80211_channel_to_frequency(int chan, enum nl80211_band band);
+static inline int
+ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
+{
+       return KHZ_TO_MHZ(ieee80211_channel_to_freq_khz(chan, band));
+}
+
+/**
+ * ieee80211_freq_khz_to_channel - convert frequency to channel number
+ * @freq: center frequency in KHz
+ * Return: The corresponding channel, or 0 if the conversion failed.
+ */
+int ieee80211_freq_khz_to_channel(u32 freq);
 
 /**
  * ieee80211_frequency_to_channel - convert frequency to channel number
- * @freq: center frequency
+ * @freq: center frequency in MHz
  * Return: The corresponding channel, or 0 if the conversion failed.
  */
-int ieee80211_frequency_to_channel(int freq);
+static inline int
+ieee80211_frequency_to_channel(int freq)
+{
+       return ieee80211_freq_khz_to_channel(MHZ_TO_KHZ(freq));
+}
+
+/**
+ * ieee80211_get_channel_khz - get channel struct from wiphy for specified
+ * frequency
+ * @wiphy: the struct wiphy to get the channel for
+ * @freq: the center frequency (in KHz) of the channel
+ * Return: The channel struct from @wiphy at @freq.
+ */
+struct ieee80211_channel *
+ieee80211_get_channel_khz(struct wiphy *wiphy, u32 freq);
 
 /**
  * ieee80211_get_channel - get channel struct from wiphy for specified frequency
  *
  * @wiphy: the struct wiphy to get the channel for
- * @freq: the center frequency of the channel
- *
+ * @freq: the center frequency (in MHz) of the channel
  * Return: The channel struct from @wiphy at @freq.
  */
-struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq);
+static inline struct ieee80211_channel *
+ieee80211_get_channel(struct wiphy *wiphy, int freq)
+{
+       return ieee80211_get_channel_khz(wiphy, MHZ_TO_KHZ(freq));
+}
 
 /**
  * ieee80211_get_response_rate - get basic rate for a given rate
@@ -6135,12 +6224,16 @@ void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
 /**
  * cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
  * @dev: network device
- * @buf: deauthentication frame (header + body)
+ * @buf: received management frame (header + body)
  * @len: length of the frame data
  *
  * This function is called whenever a received deauthentication or dissassoc
  * frame has been dropped in station mode because of MFP being used but the
- * frame was not protected. This function may sleep.
+ * frame was not protected. This is also used to notify reception of a Beacon
+ * frame that was dropped because it did not include a valid MME MIC while
+ * beacon protection was enabled (BIGTK configured in station mode).
+ *
+ * This function may sleep.
  */
 void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev,
                                  const u8 *buf, size_t len);
@@ -7202,6 +7295,19 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
 bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
                                          u8 *op_class);
 
+/**
+ * ieee80211_chandef_to_khz - convert chandef to frequency in KHz
+ *
+ * @chandef: the chandef to convert
+ *
+ * Returns the center frequency of chandef (1st segment) in KHz.
+ */
+static inline u32
+ieee80211_chandef_to_khz(const struct cfg80211_chan_def *chandef)
+{
+       return MHZ_TO_KHZ(chandef->center_freq1) + chandef->freq1_offset;
+}
+
 /*
  * cfg80211_tdls_oper_request - request userspace to perform TDLS operation
  * @dev: the device on which the operation is requested
index 97fec4d310acfd82e0bbf91b66ea11b9a5d1d4ac..0d48e679efb0fda030bd31da4477dc87ef78c835 100644 (file)
@@ -508,6 +508,7 @@ struct ieee80211_ftm_responder_params {
  *     mode only, set if the AP advertises TWT responder role)
  * @twt_responder: does this BSS support TWT requester (relevant for managed
  *     mode only, set if the AP advertises TWT responder role)
+ * @twt_protected: does this BSS support protected TWT frames
  * @assoc: association status
  * @ibss_joined: indicates whether this station is part of an IBSS
  *     or not
@@ -603,7 +604,7 @@ struct ieee80211_ftm_responder_params {
  *     nontransmitted BSSIDs
  * @profile_periodicity: the least number of beacon frames need to be received
  *     in order to discover all the nontransmitted BSSIDs in the set.
- * @he_operation: HE operation information of the AP we are connected to
+ * @he_oper: HE operation information of the AP we are connected to
  * @he_obss_pd: OBSS Packet Detection parameters.
  * @he_bss_color: BSS coloring settings, if BSS supports HE
  */
@@ -618,6 +619,7 @@ struct ieee80211_bss_conf {
        bool he_support;
        bool twt_requester;
        bool twt_responder;
+       bool twt_protected;
        /* association related data */
        bool assoc, ibss_joined;
        bool ibss_creator;
@@ -666,7 +668,10 @@ struct ieee80211_bss_conf {
        u8 bssid_indicator;
        bool ema_ap;
        u8 profile_periodicity;
-       struct ieee80211_he_operation he_operation;
+       struct {
+               u32 params;
+               u16 nss_set;
+       } he_oper;
        struct ieee80211_he_obss_pd he_obss_pd;
        struct cfg80211_he_bss_color he_bss_color;
 };
@@ -818,6 +823,8 @@ enum mac80211_tx_info_flags {
  * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
  * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
  * @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup
+ * @IEEE80211_TX_CTRL_HW_80211_ENCAP: This frame uses hardware encapsulation
+ *     (header conversion)
  *
  * These flags are used in tx_info->control.flags.
  */
@@ -1333,6 +1340,7 @@ enum mac80211_rx_encoding {
  * @freq: frequency the radio was tuned to when receiving this frame, in MHz
  *     This field must be set for management frames, but isn't strictly needed
  *     for data (other) frames - for those it only affects radiotap reporting.
+ * @freq_offset: @freq has a positive offset of 500Khz.
  * @signal: signal strength when receiving this frame, either in dBm, in dB or
  *     unspecified depending on the hardware capabilities flags
  *     @IEEE80211_HW_SIGNAL_*
@@ -1363,7 +1371,7 @@ struct ieee80211_rx_status {
        u32 device_timestamp;
        u32 ampdu_reference;
        u32 flag;
-       u16 freq;
+       u16 freq: 13, freq_offset: 1;
        u8 enc_flags;
        u8 encoding:2, bw:3, he_ru:3;
        u8 he_gi:2, he_dcm:1;
@@ -1379,6 +1387,13 @@ struct ieee80211_rx_status {
        u8 zero_length_psdu_type;
 };
 
+static inline u32
+ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
+{
+       return MHZ_TO_KHZ(rx_status->freq) +
+              (rx_status->freq_offset ? 500 : 0);
+}
+
 /**
  * struct ieee80211_vendor_radiotap - vendor radiotap data information
  * @present: presence bitmap for this vendor namespace
@@ -1620,6 +1635,8 @@ enum ieee80211_vif_flags {
  *     monitor interface (if that is requested.)
  * @probe_req_reg: probe requests should be reported to mac80211 for this
  *     interface.
+ * @rx_mcast_action_reg: multicast Action frames should be reported to mac80211
+ *     for this interface.
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void \*).
  * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
@@ -1647,7 +1664,8 @@ struct ieee80211_vif {
        struct dentry *debugfs_dir;
 #endif
 
-       unsigned int probe_req_reg;
+       bool probe_req_reg;
+       bool rx_mcast_action_reg;
 
        bool txqs_stopped[IEEE80211_NUM_ACS];
 
@@ -3091,6 +3109,8 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * @FIF_PSPOLL: pass PS Poll frames
  *
  * @FIF_PROBE_REQ: pass probe request frames
+ *
+ * @FIF_MCAST_ACTION: pass multicast Action frames
  */
 enum ieee80211_filter_flags {
        FIF_ALLMULTI            = 1<<1,
@@ -3101,6 +3121,7 @@ enum ieee80211_filter_flags {
        FIF_OTHER_BSS           = 1<<6,
        FIF_PSPOLL              = 1<<7,
        FIF_PROBE_REQ           = 1<<8,
+       FIF_MCAST_ACTION        = 1<<9,
 };
 
 /**
@@ -3117,7 +3138,10 @@ enum ieee80211_filter_flags {
  * @IEEE80211_AMPDU_RX_START: start RX aggregation
  * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation
  * @IEEE80211_AMPDU_TX_START: start TX aggregation, the driver must either
- *     call ieee80211_start_tx_ba_cb_irqsafe() or return the special
+ *     call ieee80211_start_tx_ba_cb_irqsafe() or
+ *     call ieee80211_start_tx_ba_cb_irqsafe() with status
+ *     %IEEE80211_AMPDU_TX_START_DELAY_ADDBA to delay addba after
+ *     ieee80211_start_tx_ba_cb_irqsafe is called, or just return the special
  *     status %IEEE80211_AMPDU_TX_START_IMMEDIATE.
  * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational
  * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting
@@ -3143,6 +3167,7 @@ enum ieee80211_ampdu_mlme_action {
 };
 
 #define IEEE80211_AMPDU_TX_START_IMMEDIATE 1
+#define IEEE80211_AMPDU_TX_START_DELAY_ADDBA 2
 
 /**
  * struct ieee80211_ampdu_params - AMPDU action parameters
index 3469750df0f44542bce0a97aa23360cbfe7079fc..09a3099886e5f692970e2a0c2109f00f7612379e 100644 (file)
@@ -231,13 +231,6 @@ struct ieee80211_regdomain {
        struct ieee80211_reg_rule reg_rules[];
 };
 
-#define MHZ_TO_KHZ(freq) ((freq) * 1000)
-#define KHZ_TO_MHZ(freq) ((freq) / 1000)
-#define DBI_TO_MBI(gain) ((gain) * 100)
-#define MBI_TO_DBI(gain) ((gain) / 100)
-#define DBM_TO_MBM(gain) ((gain) * 100)
-#define MBM_TO_DBM(gain) ((gain) / 100)
-
 #define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags)   \
 {                                                                      \
        .freq_range.start_freq_khz = MHZ_TO_KHZ(start),                 \
index 2b691161830f864ede631508bf07a01c47d24e7e..9679d561f7d0a4e7cd0b7776388c0e12d63da989 100644 (file)
  *     four bytes for vendor frames including the OUI. The registration
  *     cannot be dropped, but is removed automatically when the netlink
  *     socket is closed. Multiple registrations can be made.
+ *     The %NL80211_ATTR_RECEIVE_MULTICAST flag attribute can be given if
+ *     %NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS is available, in which
+ *     case the registration can also be modified to include/exclude the
+ *     flag, rather than requiring unregistration to change it.
  * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
  *     backward compatibility
  * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
  * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration
  *     is passed using %NL80211_ATTR_TID_CONFIG attribute.
  *
+ * @NL80211_CMD_UNPROT_BEACON: Unprotected or incorrectly protected Beacon
+ *     frame. This event is used to indicate that a received Beacon frame was
+ *     dropped because it did not include a valid MME MIC while beacon
+ *     protection was enabled (BIGTK configured in station mode).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1377,6 +1386,8 @@ enum nl80211_commands {
 
        NL80211_CMD_SET_TID_CONFIG,
 
+       NL80211_CMD_UNPROT_BEACON,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -2470,6 +2481,9 @@ enum nl80211_commands {
  *     no roaming occurs between the reauth threshold and PMK expiration,
  *     disassociation is still forced.
  *
+ * @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the
+ *     %NL80211_CMD_REGISTER_FRAME command, see the description there.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2945,6 +2959,8 @@ enum nl80211_attrs {
        NL80211_ATTR_PMK_LIFETIME,
        NL80211_ATTR_PMK_REAUTH_THRESHOLD,
 
+       NL80211_ATTR_RECEIVE_MULTICAST,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -5674,6 +5690,8 @@ enum nl80211_feature_flags {
  *
  * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection
  *     and can receive key configuration for BIGTK using key indexes 6 and 7.
+ * @NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT: The driver supports Beacon
+ *     protection as a client only and cannot transmit protected beacons.
  *
  * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the
  *     forwarding of preauth frames over the control port. They are then
@@ -5684,6 +5702,9 @@ enum nl80211_feature_flags {
  * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations
  *      in IBSS mode, essentially by dropping their state.
  *
+ * @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations
+ *     are possible for multicast frames and those will be reported properly.
+ *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
@@ -5735,6 +5756,8 @@ enum nl80211_ext_feature_index {
        NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH,
        NL80211_EXT_FEATURE_PROTECTED_TWT,
        NL80211_EXT_FEATURE_DEL_IBSS_STA,
+       NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
+       NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
index 33da6f738c999270ebdfd1364cf30f57b8797166..c2d5f512526d8f8f880d613fbe40356378fe59f1 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2020 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -448,6 +448,45 @@ static void sta_addba_resp_timer_expired(struct timer_list *t)
        ieee80211_stop_tx_ba_session(&sta->sta, tid);
 }
 
+static void ieee80211_send_addba_with_timeout(struct sta_info *sta,
+                                             struct tid_ampdu_tx *tid_tx)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_local *local = sta->local;
+       u8 tid = tid_tx->tid;
+       u16 buf_size;
+
+       /* activate the timer for the recipient's addBA response */
+       mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
+       ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n",
+              sta->sta.addr, tid);
+
+       spin_lock_bh(&sta->lock);
+       sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
+       sta->ampdu_mlme.addba_req_num[tid]++;
+       spin_unlock_bh(&sta->lock);
+
+       if (sta->sta.he_cap.has_he) {
+               buf_size = local->hw.max_tx_aggregation_subframes;
+       } else {
+               /*
+                * We really should use what the driver told us it will
+                * transmit as the maximum, but certain APs (e.g. the
+                * LinkSys WRT120N with FW v1.0.07 build 002 Jun 18 2012)
+                * will crash when we use a lower number.
+                */
+               buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
+       }
+
+       /* send AddBA request */
+       ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
+                                    tid_tx->dialog_token,
+                                    sta->tid_seq[tid] >> 4,
+                                    buf_size, tid_tx->timeout);
+
+       WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
+}
+
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
        struct tid_ampdu_tx *tid_tx;
@@ -462,7 +501,6 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
                .timeout = 0,
        };
        int ret;
-       u16 buf_size;
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
@@ -485,7 +523,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 
        params.ssn = sta->tid_seq[tid] >> 4;
        ret = drv_ampdu_action(local, sdata, &params);
-       if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
+       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
@@ -508,32 +548,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
                return;
        }
 
-       /* activate the timer for the recipient's addBA response */
-       mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
-       ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n",
-              sta->sta.addr, tid);
-
-       spin_lock_bh(&sta->lock);
-       sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
-       sta->ampdu_mlme.addba_req_num[tid]++;
-       spin_unlock_bh(&sta->lock);
-
-       if (sta->sta.he_cap.has_he) {
-               buf_size = local->hw.max_tx_aggregation_subframes;
-       } else {
-               /*
-                * We really should use what the driver told us it will
-                * transmit as the maximum, but certain APs (e.g. the
-                * LinkSys WRT120N with FW v1.0.07 build 002 Jun 18 2012)
-                * will crash when we use a lower number.
-                */
-               buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
-       }
-
-       /* send AddBA request */
-       ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
-                                    tid_tx->dialog_token, params.ssn,
-                                    buf_size, tid_tx->timeout);
+       ieee80211_send_addba_with_timeout(sta, tid_tx);
 }
 
 /*
@@ -754,6 +769,12 @@ void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
        if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
                return;
 
+       if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) {
+               ieee80211_send_addba_with_timeout(sta, tid_tx);
+               /* RESPONSE_RECEIVED state whould trigger the flow again */
+               return;
+       }
+
        if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
                ieee80211_agg_tx_operational(local, sta, tid);
 }
index 0f72813fed53e4d94f8f1923da8284a91cd0346a..548a384b0509902d153cbfba623432441547af49 100644 (file)
@@ -994,7 +994,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                      BSS_CHANGED_TWT |
                      BSS_CHANGED_HE_OBSS_PD |
                      BSS_CHANGED_HE_BSS_COLOR;
-       int err;
+       int i, err;
        int prev_beacon_int;
 
        old = sdata_dereference(sdata->u.ap.beacon, sdata);
@@ -1085,6 +1085,17 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
                                        IEEE80211_P2P_OPPPS_ENABLE_BIT;
 
+       sdata->beacon_rate_set = false;
+       if (wiphy_ext_feature_isset(local->hw.wiphy,
+                                   NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
+               for (i = 0; i < NUM_NL80211_BANDS; i++) {
+                       sdata->beacon_rateidx_mask[i] =
+                               params->beacon_rate.control[i].legacy;
+                       if (sdata->beacon_rateidx_mask[i])
+                               sdata->beacon_rate_set = true;
+               }
+       }
+
        err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
        if (err < 0) {
                ieee80211_vif_release_channel(sdata);
@@ -1189,6 +1200,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        ieee80211_free_keys(sdata, true);
 
        sdata->vif.bss_conf.enable_beacon = false;
+       sdata->beacon_rate_set = false;
        sdata->vif.bss_conf.ssid_len = 0;
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
@@ -1949,6 +1961,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        const u8 *old_ie;
        struct ieee80211_sub_if_data *sdata = container_of(ifmsh,
                                        struct ieee80211_sub_if_data, u.mesh);
+       int i;
 
        /* allocate information elements */
        new_ie = NULL;
@@ -1987,6 +2000,17 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
        sdata->vif.bss_conf.dtim_period = setup->dtim_period;
 
+       sdata->beacon_rate_set = false;
+       if (wiphy_ext_feature_isset(sdata->local->hw.wiphy,
+                                   NL80211_EXT_FEATURE_BEACON_RATE_LEGACY)) {
+               for (i = 0; i < NUM_NL80211_BANDS; i++) {
+                       sdata->beacon_rateidx_mask[i] =
+                               setup->beacon_rate.control[i].legacy;
+                       if (sdata->beacon_rateidx_mask[i])
+                               sdata->beacon_rate_set = true;
+               }
+       }
+
        return 0;
 }
 
@@ -3287,6 +3311,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       if (params->chandef.chan->freq_offset) {
+               /* this may work, but is untested */
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 
        ch_switch.timestamp = 0;
@@ -3398,41 +3428,43 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
        return 0;
 }
 
-static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
+static void
+ieee80211_update_mgmt_frame_registrations(struct wiphy *wiphy,
                                          struct wireless_dev *wdev,
-                                         u16 frame_type, bool reg)
+                                         struct mgmt_frame_regs *upd)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+       u32 preq_mask = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
+       u32 action_mask = BIT(IEEE80211_STYPE_ACTION >> 4);
+       bool global_change, intf_change;
+
+       global_change =
+               (local->probe_req_reg != !!(upd->global_stypes & preq_mask)) ||
+               (local->rx_mcast_action_reg !=
+                !!(upd->global_mcast_stypes & action_mask));
+       local->probe_req_reg = upd->global_stypes & preq_mask;
+       local->rx_mcast_action_reg = upd->global_mcast_stypes & action_mask;
+
+       intf_change = (sdata->vif.probe_req_reg !=
+                      !!(upd->interface_stypes & preq_mask)) ||
+               (sdata->vif.rx_mcast_action_reg !=
+                !!(upd->interface_mcast_stypes & action_mask));
+       sdata->vif.probe_req_reg = upd->interface_stypes & preq_mask;
+       sdata->vif.rx_mcast_action_reg =
+               upd->interface_mcast_stypes & action_mask;
+
+       if (!local->open_count)
+               return;
 
-       switch (frame_type) {
-       case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
-               if (reg) {
-                       local->probe_req_reg++;
-                       sdata->vif.probe_req_reg++;
-               } else {
-                       if (local->probe_req_reg)
-                               local->probe_req_reg--;
-
-                       if (sdata->vif.probe_req_reg)
-                               sdata->vif.probe_req_reg--;
-               }
-
-               if (!local->open_count)
-                       break;
-
-               if (sdata->vif.probe_req_reg == 1)
-                       drv_config_iface_filter(local, sdata, FIF_PROBE_REQ,
-                                               FIF_PROBE_REQ);
-               else if (sdata->vif.probe_req_reg == 0)
-                       drv_config_iface_filter(local, sdata, 0,
-                                               FIF_PROBE_REQ);
+       if (intf_change && ieee80211_sdata_running(sdata))
+               drv_config_iface_filter(local, sdata,
+                                       sdata->vif.probe_req_reg ?
+                                               FIF_PROBE_REQ : 0,
+                                       FIF_PROBE_REQ);
 
+       if (global_change)
                ieee80211_configure_filter(local);
-               break;
-       default:
-               break;
-       }
 }
 
 static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
@@ -4017,7 +4049,8 @@ const struct cfg80211_ops mac80211_config_ops = {
        .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
        .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
        .set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
-       .mgmt_frame_register = ieee80211_mgmt_frame_register,
+       .update_mgmt_frame_registrations =
+               ieee80211_update_mgmt_frame_registrations,
        .set_antenna = ieee80211_set_antenna,
        .get_antenna = ieee80211_get_antenna,
        .set_rekey_data = ieee80211_set_rekey_data,
index 9c94baaf693cbb531e57fafdf26144667a4fe68a..e6e192f53e4e0eab94877e0ab5ad786478d3ebbc 100644 (file)
@@ -533,6 +533,7 @@ static void ieee80211_del_chanctx(struct ieee80211_local *local,
                struct cfg80211_chan_def *chandef = &local->_oper_chandef;
                chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
                chandef->center_freq1 = chandef->chan->center_freq;
+               chandef->freq1_offset = chandef->chan->freq_offset;
                chandef->center_freq2 = 0;
 
                /* NOTE: Disabling radar is only valid here for
index 3dbe7c5cefd1f1cddf0efcc9d62826c0da84cb4f..d7e955127d5c1423913b744949ed2d34aefe2154 100644 (file)
@@ -236,7 +236,7 @@ IEEE80211_IF_FILE_R(hw_queues);
 
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
-IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
+IEEE80211_IF_FILE(aid, vif.bss_conf.aid, DEC);
 IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
 
 static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
index 1087f715338b5626e81e15bd3c1bfc83bbff5b4a..f520552b22bea2a96f5e2196a7344fedbbdb5901 100644 (file)
@@ -57,17 +57,14 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 
 void
 ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
-                       const struct ieee80211_he_operation *he_op_ie_elem)
+                       const struct ieee80211_he_operation *he_op_ie)
 {
-       struct ieee80211_he_operation *he_operation =
-                                       &vif->bss_conf.he_operation;
-
-       if (!he_op_ie_elem) {
-               memset(he_operation, 0, sizeof(*he_operation));
+       memset(&vif->bss_conf.he_oper, 0, sizeof(vif->bss_conf.he_oper));
+       if (!he_op_ie)
                return;
-       }
 
-       vif->bss_conf.he_operation = *he_op_ie_elem;
+       vif->bss_conf.he_oper.params = __le32_to_cpu(he_op_ie->he_oper_params);
+       vif->bss_conf.he_oper.nss_set = __le16_to_cpu(he_op_ie->he_mcs_nss_set);
 }
 
 void
index d40744903fa90f596435d7e9fdb4d46ec39683b3..2479cd48fed096e6ac283989c5d00f101a20050d 100644 (file)
@@ -1758,6 +1758,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        int i;
        int ret;
 
+       if (params->chandef.chan->freq_offset) {
+               /* this may work, but is untested */
+               return -EOPNOTSUPP;
+       }
+
        ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
                                            &params->chandef,
                                            sdata->wdev.iftype);
index f8ed4f621f7f85dfb9018c4304f35e48e7b49a5d..8cbae66b5cdb7d000686d9773e8a7a8593691a14 100644 (file)
@@ -450,8 +450,6 @@ struct ieee80211_if_managed {
 
        u8 bssid[ETH_ALEN] __aligned(2);
 
-       u16 aid;
-
        bool powersave; /* powersave requested for this iface */
        bool broken_ap; /* AP is broken -- turn off powersave */
        bool have_beacon;
@@ -964,6 +962,10 @@ struct ieee80211_sub_if_data {
        bool rc_has_vht_mcs_mask[NUM_NL80211_BANDS];
        u16 rc_rateidx_vht_mcs_mask[NUM_NL80211_BANDS][NL80211_VHT_NSS_MAX];
 
+       /* Beacon frame (non-MCS) rate (as a bitmap) */
+       u32 beacon_rateidx_mask[NUM_NL80211_BANDS];
+       bool beacon_rate_set;
+
        union {
                struct ieee80211_if_ap ap;
                struct ieee80211_if_wds wds;
@@ -1169,7 +1171,8 @@ struct ieee80211_local {
        /* number of interfaces with corresponding FIF_ flags */
        int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll,
            fif_probe_req;
-       int probe_req_reg;
+       bool probe_req_reg;
+       bool rx_mcast_action_reg;
        unsigned int filter_flags; /* FIF_* */
 
        bool wiphy_ciphers_allocated;
index d069825705d6dc9cf78d6fc9e2ad0432509bc751..f900c84fb40f59c38eb2261e042825fc61cb2d0c 100644 (file)
@@ -644,6 +644,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                        local->fif_probe_req++;
                }
 
+               if (sdata->vif.probe_req_reg)
+                       drv_config_iface_filter(local, sdata,
+                                               FIF_PROBE_REQ,
+                                               FIF_PROBE_REQ);
+
                if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
                    sdata->vif.type != NL80211_IFTYPE_NAN)
                        changed |= ieee80211_reset_erp_info(sdata);
index 6423173bb87ed4bb0df0b17c59e09644cf2e0e56..06c90d3606332bb1202a34d191b00a3842f1838e 100644 (file)
@@ -64,6 +64,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        if (local->fif_pspoll)
                new_flags |= FIF_PSPOLL;
 
+       if (local->rx_mcast_action_reg)
+               new_flags |= FIF_MCAST_ACTION;
+
        spin_lock_bh(&local->filter_lock);
        changed_flags = local->filter_flags ^ new_flags;
 
@@ -104,13 +107,15 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
                chandef.chan = local->tmp_channel;
                chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
                chandef.center_freq1 = chandef.chan->center_freq;
+               chandef.freq1_offset = chandef.chan->freq_offset;
        } else
                chandef = local->_oper_chandef;
 
        WARN(!cfg80211_chandef_valid(&chandef),
-            "control:%d MHz width:%d center: %d/%d MHz",
-            chandef.chan->center_freq, chandef.width,
-            chandef.center_freq1, chandef.center_freq2);
+            "control:%d.%03d MHz width:%d center: %d.%03d/%d MHz",
+            chandef.chan->center_freq, chandef.chan->freq_offset,
+            chandef.width, chandef.center_freq1, chandef.freq1_offset,
+            chandef.center_freq2);
 
        if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef))
                local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
index 36978a0e500017d0c193fb5bfb86a8f61f210206..5930d07b1e43d31533d515b06cecf413b151f90c 100644 (file)
@@ -994,6 +994,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        /* stop the beacon */
        ifmsh->mesh_id_len = 0;
        sdata->vif.bss_conf.enable_beacon = false;
+       sdata->beacon_rate_set = false;
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
index 16d75da0996a1636d496d85636a76ec2b29d567b..a259b4487b6001f02d6554a6b0ca4b8d176dbd51 100644 (file)
@@ -162,6 +162,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        chandef->chan = channel;
        chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
        chandef->center_freq1 = channel->center_freq;
+       chandef->freq1_offset = channel->freq_offset;
 
        if (!ht_oper || !sta_ht_cap.ht_supported) {
                ret = IEEE80211_STA_DISABLE_HT |
@@ -396,9 +397,12 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
                return 0;
 
        sdata_info(sdata,
-                  "AP %pM changed bandwidth, new config is %d MHz, width %d (%d/%d MHz)\n",
-                  ifmgd->bssid, chandef.chan->center_freq, chandef.width,
-                  chandef.center_freq1, chandef.center_freq2);
+                  "AP %pM changed bandwidth, new config is %d.%03d MHz, "
+                  "width %d (%d.%03d/%d MHz)\n",
+                  ifmgd->bssid, chandef.chan->center_freq,
+                  chandef.chan->freq_offset, chandef.width,
+                  chandef.center_freq1, chandef.freq1_offset,
+                  chandef.center_freq2);
 
        if (flags != (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
                                      IEEE80211_STA_DISABLE_VHT |
@@ -1364,10 +1368,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
                                     IEEE80211_CHAN_DISABLED)) {
                sdata_info(sdata,
-                          "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+                          "AP %pM switches to unsupported channel "
+                          "(%d.%03d MHz, width:%d, CF1/2: %d.%03d/%d MHz), "
+                          "disconnecting\n",
                           ifmgd->associated->bssid,
                           csa_ie.chandef.chan->center_freq,
+                          csa_ie.chandef.chan->freq_offset,
                           csa_ie.chandef.width, csa_ie.chandef.center_freq1,
+                          csa_ie.chandef.freq1_offset,
                           csa_ie.chandef.center_freq2);
                ieee80211_queue_work(&local->hw,
                                     &ifmgd->csa_connection_drop_work);
@@ -2948,10 +2956,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        }
 
        if (status_code != WLAN_STATUS_SUCCESS) {
+               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+
+               if (auth_alg == WLAN_AUTH_SAE &&
+                   status_code == WLAN_STATUS_ANTI_CLOG_REQUIRED)
+                       return;
+
                sdata_info(sdata, "%pM denied authentication (status %d)\n",
                           mgmt->sa, status_code);
                ieee80211_destroy_auth_data(sdata, false);
-               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
                event.u.mlme.status = MLME_DENIED;
                event.u.mlme.reason = status_code;
                drv_event_callback(sdata->local, sdata, &event);
@@ -3149,15 +3162,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
                        *have_higher_than_11mbit = true;
 
                /*
-                * Skip HT and VHT BSS membership selectors since they're not
-                * rates.
+                * Skip HT, VHT and HE BSS membership selectors since they're
+                * not rates.
                 *
                 * Note: Even though the membership selector and the basic
                 *       rate flag share the same bit, they are not exactly
                 *       the same.
                 */
                if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
-                   supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY))
+                   supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) ||
+                   supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY))
                        continue;
 
                for (j = 0; j < sband->n_bitrates; j++) {
@@ -3249,7 +3263,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                return false;
        }
 
-       ifmgd->aid = aid;
+       sdata->vif.bss_conf.aid = aid;
        ifmgd->tdls_chan_switch_prohibited =
                elems->ext_capab && elems->ext_capab_len >= 5 &&
                (elems->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED);
@@ -3384,10 +3398,19 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                                                  sta);
 
                bss_conf->he_support = sta->sta.he_cap.has_he;
+               if (elems->rsnx && elems->rsnx_len &&
+                   (elems->rsnx[0] & WLAN_RSNX_CAPA_PROTECTED_TWT) &&
+                   wiphy_ext_feature_isset(local->hw.wiphy,
+                                           NL80211_EXT_FEATURE_PROTECTED_TWT))
+                       bss_conf->twt_protected = true;
+               else
+                       bss_conf->twt_protected = false;
+
                changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
        } else {
                bss_conf->he_support = false;
                bss_conf->twt_requester = false;
+               bss_conf->twt_protected = false;
        }
 
        if (bss_conf->he_support) {
@@ -3521,9 +3544,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
                bss_conf->protected_keep_alive = false;
        }
 
-       /* set AID and assoc capability,
+       /* set assoc capability (AID was already set earlier),
         * ieee80211_set_associated() will tell the driver */
-       bss_conf->aid = aid;
        bss_conf->assoc_capability = capab_info;
        ieee80211_set_associated(sdata, cbss, changed);
 
@@ -3661,7 +3683,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
        sdata_assert_lock(sdata);
 
-       channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+       channel = ieee80211_get_channel_khz(local->hw.wiphy,
+                                       ieee80211_rx_status_to_khz(rx_status));
        if (!channel)
                return;
 
@@ -3877,7 +3900,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
+       if (ieee80211_rx_status_to_khz(rx_status) !=
+           ieee80211_channel_to_khz(chanctx_conf->def.chan)) {
                rcu_read_unlock();
                return;
        }
@@ -3948,7 +3972,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                          mgmt->bssid, bssid);
 
        if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
-           ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
+           ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
                if (local->hw.conf.dynamic_ps_timeout > 0) {
                        if (local->hw.conf.flags & IEEE80211_CONF_PS) {
                                local->hw.conf.flags &= ~IEEE80211_CONF_PS;
@@ -5022,8 +5046,16 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                 * doesn't happen any more, but keep the workaround so
                 * in case some *other* APs are buggy in different ways
                 * we can connect -- with a warning.
+                * Allow this workaround only in case the AP provided at least
+                * one rate.
                 */
-               if (!basic_rates && min_rate_index >= 0) {
+               if (min_rate_index < 0) {
+                       sdata_info(sdata,
+                                  "No legacy rates in association response\n");
+
+                       sta_info_free(local, new_sta);
+                       return -EINVAL;
+               } else if (!basic_rates) {
                        sdata_info(sdata,
                                   "No basic rates, using min rate instead\n");
                        basic_rates = BIT(min_rate_index);
index c710504ccf1aa3990ac41aa6895d8dbf32a5fa56..db3b8bf756562a79c43fdb34b1f284fc47d7127c 100644 (file)
@@ -557,6 +557,10 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
        lockdep_assert_held(&local->mtx);
 
+       if (channel->freq_offset)
+               /* this may work, but is untested */
+               return -EOPNOTSUPP;
+
        if (local->use_chanctx && !local->ops->remain_on_channel)
                return -EOPNOTSUPP;
 
index 5dc3e5bc4e6422f7472f3f5fa6c5fa714fd4ca32..b11a2af55b06a0fd0712ecd0072339280e1e0e91 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2019-2020 Intel Corporation
  */
 #include <linux/netdevice.h>
 #include <linux/types.h>
@@ -490,7 +491,7 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
        tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
        tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
 
-       if (tmp_cck_tp_rate && tmp_cck_tp > tmp_mcs_tp) {
+       if (tmp_cck_tp > tmp_mcs_tp) {
                for(i = 0; i < MAX_THR_RATES; i++) {
                        minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i],
                                                       tmp_mcs_tp_rate);
index 91a13aee43784f428654206af1a1824fc1c7e02a..eaf8931e46275866be5eaf99759d442110b4985a 100644 (file)
@@ -412,6 +412,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        pos++;
 
        /* IEEE80211_RADIOTAP_CHANNEL */
+       /* TODO: frequency offset in KHz */
        put_unaligned_le16(status->freq, pos);
        pos += 2;
        if (status->bw == RATE_INFO_BW_10)
@@ -1984,8 +1985,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
                    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
-                   NUM_DEFAULT_BEACON_KEYS)
+                   NUM_DEFAULT_BEACON_KEYS) {
+                       cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+                                                    skb->data,
+                                                    skb->len);
                        return RX_DROP_MONITOR; /* unexpected BIP keyidx */
+               }
 
                rx->key = ieee80211_rx_get_bigtk(rx, mmie_keyidx);
                if (!rx->key)
@@ -2131,6 +2136,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        /* either the frame has been decrypted or will be dropped */
        status->flag |= RX_FLAG_DECRYPTED;
 
+       if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
+               cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+                                            skb->data, skb->len);
+
        return result;
 }
 
@@ -2411,8 +2420,12 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
                        return -EACCES;
                }
                if (unlikely(ieee80211_is_beacon(fc) && rx->key &&
-                            ieee80211_get_mmie_keyidx(rx->skb) < 0))
+                            ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
+                       cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+                                                    rx->skb->data,
+                                                    rx->skb->len);
                        return -EACCES;
+               }
                /*
                 * When using MFP, Action frames are not allowed prior to
                 * having configured keys.
index fdac8192a5198886986e0a7e0f6d33e8e5f17156..5db15996524f8f0b7e154e0a0cc739c07c1bbd5b 100644 (file)
@@ -275,7 +275,8 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
                        return;
        }
 
-       channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+       channel = ieee80211_get_channel_khz(local->hw.wiphy,
+                                       ieee80211_rx_status_to_khz(rx_status));
 
        if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
                return;
@@ -896,6 +897,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 
        local->scan_chandef.chan = chan;
        local->scan_chandef.center_freq1 = chan->center_freq;
+       local->scan_chandef.freq1_offset = chan->freq_offset;
        local->scan_chandef.center_freq2 = 0;
        switch (scan_req->scan_width) {
        case NL80211_BSS_CHAN_WIDTH_5:
index 36f1abaab9fffa3ad2be705cea148432e06999c6..49728047dfad610a289d9520a50acc239e9d4b5f 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright 2002-2005, Devicescape Software, Inc.
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright(c) 2020 Intel Corporation
  */
 
 #ifndef STA_INFO_H
@@ -68,6 +69,8 @@
  * @WLAN_STA_MPSP_RECIPIENT: local STA is recipient of a MPSP.
  * @WLAN_STA_PS_DELIVER: station woke up, but we're still blocking TX
  *     until pending frames are delivered
+ * @WLAN_STA_USES_ENCRYPTION: This station was configured for encryption,
+ *     so drop all packets without a key later.
  *
  * @NUM_WLAN_STA_FLAGS: number of defined flags
  */
@@ -116,6 +119,7 @@ enum ieee80211_sta_info_flags {
 #define HT_AGG_STATE_WANT_STOP         5
 #define HT_AGG_STATE_START_CB          6
 #define HT_AGG_STATE_STOP_CB           7
+#define HT_AGG_STATE_SENT_ADDBA                8
 
 DECLARE_EWMA(avg_signal, 10, 8)
 enum ieee80211_agg_stop_reason {
index fca1f54773965ad36862ed148e667ef6856957a0..8ad420db37667e84476d36dbdbd9f1febe16df0d 100644 (file)
@@ -226,12 +226,11 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata,
 static void
 ieee80211_tdls_add_aid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 *pos = skb_put(skb, 4);
 
        *pos++ = WLAN_EID_AID;
        *pos++ = 2; /* len */
-       put_unaligned_le16(ifmgd->aid, pos);
+       put_unaligned_le16(sdata->vif.bss_conf.aid, pos);
 }
 
 /* translate numbering in the WMM parameter IE to the mac80211 notation */
@@ -1567,6 +1566,10 @@ ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        u32 ch_sw_tm_ie;
        int ret;
 
+       if (chandef->chan->freq_offset)
+               /* this may work, but is untested */
+               return -EOPNOTSUPP;
+
        mutex_lock(&local->sta_mtx);
        sta = sta_info_get(sdata, addr);
        if (!sta) {
index 427f51a0a9945a8d885af104f350e821f666336e..1b4709694d2a89213a774284a5927c982c6b22f6 100644 (file)
 #define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
 
 #define CHANDEF_ENTRY  __field(u32, control_freq)                                      \
+                       __field(u32, freq_offset)                                       \
                        __field(u32, chan_width)                                        \
                        __field(u32, center_freq1)                                      \
+                       __field(u32, freq1_offset)                                      \
                        __field(u32, center_freq2)
 #define CHANDEF_ASSIGN(c)                                                      \
                        __entry->control_freq = (c) ? ((c)->chan ? (c)->chan->center_freq : 0) : 0;     \
+                       __entry->freq_offset = (c) ? ((c)->chan ? (c)->chan->freq_offset : 0) : 0;      \
                        __entry->chan_width = (c) ? (c)->width : 0;                     \
                        __entry->center_freq1 = (c) ? (c)->center_freq1 : 0;            \
+                       __entry->freq1_offset = (c) ? (c)->freq1_offset : 0;            \
                        __entry->center_freq2 = (c) ? (c)->center_freq2 : 0;
-#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
-#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width,                     \
-                       __entry->center_freq1, __entry->center_freq2
+#define CHANDEF_PR_FMT " control:%d.%03d MHz width:%d center: %d.%03d/%d MHz"
+#define CHANDEF_PR_ARG __entry->control_freq, __entry->freq_offset, __entry->chan_width, \
+                       __entry->center_freq1, __entry->freq1_offset, __entry->center_freq2
 
 #define MIN_CHANDEF_ENTRY                                                              \
                        __field(u32, min_control_freq)                                  \
+                       __field(u32, min_freq_offset)                                   \
                        __field(u32, min_chan_width)                                    \
                        __field(u32, min_center_freq1)                                  \
+                       __field(u32, min_freq1_offset)                                  \
                        __field(u32, min_center_freq2)
 
 #define MIN_CHANDEF_ASSIGN(c)                                                          \
                        __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0;     \
+                       __entry->min_freq_offset = (c)->chan ? (c)->chan->freq_offset : 0;      \
                        __entry->min_chan_width = (c)->width;                           \
                        __entry->min_center_freq1 = (c)->center_freq1;                  \
+                       __entry->freq1_offset = (c)->freq1_offset;                      \
                        __entry->min_center_freq2 = (c)->center_freq2;
-#define MIN_CHANDEF_PR_FMT     " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
-#define MIN_CHANDEF_PR_ARG     __entry->min_control_freq, __entry->min_chan_width,     \
-                       __entry->min_center_freq1, __entry->min_center_freq2
+#define MIN_CHANDEF_PR_FMT     " min_control:%d.%03d MHz min_width:%d min_center: %d.%03d/%d MHz"
+#define MIN_CHANDEF_PR_ARG     __entry->min_control_freq, __entry->min_freq_offset,    \
+                       __entry->min_chan_width,                                        \
+                       __entry->min_center_freq1, __entry->min_freq1_offset,           \
+                       __entry->min_center_freq2
 
 #define CHANCTX_ENTRY  CHANDEF_ENTRY                                                   \
                        MIN_CHANDEF_ENTRY                                               \
@@ -412,6 +422,7 @@ TRACE_EVENT(drv_bss_info_changed,
                __field(s32, cqm_rssi_hyst)
                __field(u32, channel_width)
                __field(u32, channel_cfreq1)
+               __field(u32, channel_cfreq1_offset)
                __dynamic_array(u32, arp_addr_list,
                                info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
                                        IEEE80211_BSS_ARP_ADDR_LIST_LEN :
@@ -452,6 +463,7 @@ TRACE_EVENT(drv_bss_info_changed,
                __entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
                __entry->channel_width = info->chandef.width;
                __entry->channel_cfreq1 = info->chandef.center_freq1;
+               __entry->channel_cfreq1_offset = info->chandef.freq1_offset;
                __entry->arp_addr_cnt = info->arp_addr_cnt;
                memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
                       sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
@@ -1223,6 +1235,7 @@ TRACE_EVENT(drv_remain_on_channel,
                LOCAL_ENTRY
                VIF_ENTRY
                __field(int, center_freq)
+               __field(int, freq_offset)
                __field(unsigned int, duration)
                __field(u32, type)
        ),
@@ -1231,14 +1244,16 @@ TRACE_EVENT(drv_remain_on_channel,
                LOCAL_ASSIGN;
                VIF_ASSIGN;
                __entry->center_freq = chan->center_freq;
+               __entry->freq_offset = chan->freq_offset;
                __entry->duration = duration;
                __entry->type = type;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT  VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
+               LOCAL_PR_FMT  VIF_PR_FMT " freq:%d.%03dMHz duration:%dms type=%d",
                LOCAL_PR_ARG, VIF_PR_ARG,
-               __entry->center_freq, __entry->duration, __entry->type
+               __entry->center_freq, __entry->freq_offset,
+               __entry->duration, __entry->type
        )
 );
 
@@ -1546,8 +1561,10 @@ struct trace_vif_entry {
 
 struct trace_chandef_entry {
        u32 control_freq;
+       u32 freq_offset;
        u32 chan_width;
        u32 center_freq1;
+       u32 freq1_offset;
        u32 center_freq2;
 } __packed;
 
@@ -1597,18 +1614,26 @@ TRACE_EVENT(drv_switch_vif_chanctx,
                                        sizeof(local_vifs[i].vif.vif_name));
                                SWITCH_ENTRY_ASSIGN(old_chandef.control_freq,
                                                old_ctx->def.chan->center_freq);
+                               SWITCH_ENTRY_ASSIGN(old_chandef.freq_offset,
+                                               old_ctx->def.chan->freq_offset);
                                SWITCH_ENTRY_ASSIGN(old_chandef.chan_width,
                                                    old_ctx->def.width);
                                SWITCH_ENTRY_ASSIGN(old_chandef.center_freq1,
                                                    old_ctx->def.center_freq1);
+                               SWITCH_ENTRY_ASSIGN(old_chandef.freq1_offset,
+                                                   old_ctx->def.freq1_offset);
                                SWITCH_ENTRY_ASSIGN(old_chandef.center_freq2,
                                                    old_ctx->def.center_freq2);
                                SWITCH_ENTRY_ASSIGN(new_chandef.control_freq,
                                                new_ctx->def.chan->center_freq);
+                               SWITCH_ENTRY_ASSIGN(new_chandef.freq_offset,
+                                               new_ctx->def.chan->freq_offset);
                                SWITCH_ENTRY_ASSIGN(new_chandef.chan_width,
                                                    new_ctx->def.width);
                                SWITCH_ENTRY_ASSIGN(new_chandef.center_freq1,
                                                    new_ctx->def.center_freq1);
+                               SWITCH_ENTRY_ASSIGN(new_chandef.freq1_offset,
+                                                   new_ctx->def.freq1_offset);
                                SWITCH_ENTRY_ASSIGN(new_chandef.center_freq2,
                                                    new_ctx->def.center_freq2);
                        }
index 9849c14694dbc0b401b248cf1a6e635dd7347a33..47f460c8bd74fcf68a1ed6e80c57e737946d4218 100644 (file)
@@ -4883,7 +4883,10 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
        txrc.bss_conf = &sdata->vif.bss_conf;
        txrc.skb = skb;
        txrc.reported_rate.idx = -1;
-       txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
+       if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band])
+               txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band];
+       else
+               txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
        txrc.bss = true;
        rate_control_get_rate(sdata, NULL, &txrc);
 
@@ -5006,7 +5009,7 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
        pspoll = skb_put_zero(skb, sizeof(*pspoll));
        pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
                                            IEEE80211_STYPE_PSPOLL);
-       pspoll->aid = cpu_to_le16(ifmgd->aid);
+       pspoll->aid = cpu_to_le16(sdata->vif.bss_conf.aid);
 
        /* aid in PS-Poll has its two MSBs each set to 1 */
        pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
index 632f07401850dd2bfa10bb98efe2c359a9cb5c2a..9c6045f9c24daf051125248e49660f2eb46e5f49 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Portions of this file
  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2020 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -575,15 +575,21 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 
        switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
+               /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
                break;
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ:
+               /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */
                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
                break;
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ:
-               sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
+               if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80)
+                       sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
+               else
+                       sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
                break;
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
+               /* legacy only, no longer used by newer spec */
                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
                break;
        }
index fcac5c6366e16d5d40e69a4cdc9378c7ba926528..e111c08daa0e69d7a40698137a52e94044496bb0 100644 (file)
@@ -27,6 +27,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
                return;
 
        chandef->chan = chan;
+       chandef->freq1_offset = chan->freq_offset;
        chandef->center_freq2 = 0;
        chandef->edmg.bw_config = 0;
        chandef->edmg.channels = 0;
@@ -146,6 +147,9 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
        if (!chandef->chan)
                return false;
 
+       if (chandef->freq1_offset >= 1000)
+               return false;
+
        control_freq = chandef->chan->center_freq;
 
        switch (chandef->width) {
@@ -153,7 +157,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
        case NL80211_CHAN_WIDTH_10:
        case NL80211_CHAN_WIDTH_20:
        case NL80211_CHAN_WIDTH_20_NOHT:
-               if (chandef->center_freq1 != control_freq)
+               if (ieee80211_chandef_to_khz(chandef) !=
+                   ieee80211_channel_to_khz(chandef->chan))
                        return false;
                if (chandef->center_freq2)
                        return false;
@@ -386,10 +391,11 @@ static u32 cfg80211_get_start_freq(u32 center_freq,
 {
        u32 start_freq;
 
-       if (bandwidth <= 20)
+       bandwidth = MHZ_TO_KHZ(bandwidth);
+       if (bandwidth <= MHZ_TO_KHZ(20))
                start_freq = center_freq;
        else
-               start_freq = center_freq - bandwidth/2 + 10;
+               start_freq = center_freq - bandwidth / 2 + MHZ_TO_KHZ(10);
 
        return start_freq;
 }
@@ -399,10 +405,11 @@ static u32 cfg80211_get_end_freq(u32 center_freq,
 {
        u32 end_freq;
 
-       if (bandwidth <= 20)
+       bandwidth = MHZ_TO_KHZ(bandwidth);
+       if (bandwidth <= MHZ_TO_KHZ(20))
                end_freq = center_freq;
        else
-               end_freq = center_freq + bandwidth/2 - 10;
+               end_freq = center_freq + bandwidth / 2 - MHZ_TO_KHZ(10);
 
        return end_freq;
 }
@@ -417,8 +424,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
        start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
        end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
 
-       for (freq = start_freq; freq <= end_freq; freq += 20) {
-               c = ieee80211_get_channel(wiphy, freq);
+       for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+               c = ieee80211_get_channel_khz(wiphy, freq);
                if (!c)
                        return -EINVAL;
 
@@ -449,8 +456,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
                        return -EINVAL;
 
                ret = cfg80211_get_chans_dfs_required(wiphy,
-                                                     chandef->center_freq1,
-                                                     width);
+                                       ieee80211_chandef_to_khz(chandef),
+                                       width);
                if (ret < 0)
                        return ret;
                else if (ret > 0)
@@ -460,8 +467,8 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
                        return 0;
 
                ret = cfg80211_get_chans_dfs_required(wiphy,
-                                                     chandef->center_freq2,
-                                                     width);
+                                       MHZ_TO_KHZ(chandef->center_freq2),
+                                       width);
                if (ret < 0)
                        return ret;
                else if (ret > 0)
@@ -503,8 +510,8 @@ static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
         * DFS_AVAILABLE). Return number of usable channels
         * (require CAC). Allow DFS and non-DFS channel mix.
         */
-       for (freq = start_freq; freq <= end_freq; freq += 20) {
-               c = ieee80211_get_channel(wiphy, freq);
+       for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+               c = ieee80211_get_channel_khz(wiphy, freq);
                if (!c)
                        return -EINVAL;
 
@@ -536,8 +543,9 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
        if (width < 0)
                return false;
 
-       r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
-                                         width);
+       r1 = cfg80211_get_chans_dfs_usable(wiphy,
+                                          MHZ_TO_KHZ(chandef->center_freq1),
+                                          width);
 
        if (r1 < 0)
                return false;
@@ -546,8 +554,8 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
        case NL80211_CHAN_WIDTH_80P80:
                WARN_ON(!chandef->center_freq2);
                r2 = cfg80211_get_chans_dfs_usable(wiphy,
-                                                  chandef->center_freq2,
-                                                  width);
+                                       MHZ_TO_KHZ(chandef->center_freq2),
+                                       width);
                if (r2 < 0)
                        return false;
                break;
@@ -694,8 +702,8 @@ static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
         * If any channel in between is disabled or has not
         * had gone through CAC return false
         */
-       for (freq = start_freq; freq <= end_freq; freq += 20) {
-               c = ieee80211_get_channel(wiphy, freq);
+       for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+               c = ieee80211_get_channel_khz(wiphy, freq);
                if (!c)
                        return false;
 
@@ -724,7 +732,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
        if (width < 0)
                return false;
 
-       r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
+       r = cfg80211_get_chans_dfs_available(wiphy,
+                                            MHZ_TO_KHZ(chandef->center_freq1),
                                             width);
 
        /* If any of channels unavailable for cf1 just return */
@@ -735,8 +744,8 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
        case NL80211_CHAN_WIDTH_80P80:
                WARN_ON(!chandef->center_freq2);
                r = cfg80211_get_chans_dfs_available(wiphy,
-                                                    chandef->center_freq2,
-                                                    width);
+                                       MHZ_TO_KHZ(chandef->center_freq2),
+                                       width);
                break;
        default:
                WARN_ON(chandef->center_freq2);
@@ -757,8 +766,8 @@ static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
        start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
        end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
 
-       for (freq = start_freq; freq <= end_freq; freq += 20) {
-               c = ieee80211_get_channel(wiphy, freq);
+       for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+               c = ieee80211_get_channel_khz(wiphy, freq);
                if (!c)
                        return 0;
 
@@ -790,14 +799,14 @@ cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
                return 0;
 
        t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
-                                            chandef->center_freq1,
+                                            MHZ_TO_KHZ(chandef->center_freq1),
                                             width);
 
        if (!chandef->center_freq2)
                return t1;
 
        t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
-                                            chandef->center_freq2,
+                                            MHZ_TO_KHZ(chandef->center_freq2),
                                             width);
 
        return max(t1, t2);
@@ -813,8 +822,8 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
        start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
        end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
 
-       for (freq = start_freq; freq <= end_freq; freq += 20) {
-               c = ieee80211_get_channel(wiphy, freq);
+       for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+               c = ieee80211_get_channel_khz(wiphy, freq);
                if (!c || c->flags & prohibited_flags)
                        return false;
        }
@@ -976,13 +985,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
 
 
-       if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
+       if (!cfg80211_secondary_chans_ok(wiphy,
+                                        ieee80211_chandef_to_khz(chandef),
                                         width, prohibited_flags))
                return false;
 
        if (!chandef->center_freq2)
                return true;
-       return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
+       return cfg80211_secondary_chans_ok(wiphy,
+                                          MHZ_TO_KHZ(chandef->center_freq2),
                                           width, prohibited_flags);
 }
 EXPORT_SYMBOL(cfg80211_chandef_usable);
index 341402b4f178808191d5fe1892747d9d92cbd3d1..b795f363d004a5c6a450922745c966399ef32b5c 100644 (file)
@@ -480,9 +480,6 @@ use_default_name:
        INIT_LIST_HEAD(&rdev->bss_list);
        INIT_LIST_HEAD(&rdev->sched_scan_req_list);
        INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
-       INIT_LIST_HEAD(&rdev->mlme_unreg);
-       spin_lock_init(&rdev->mlme_unreg_lock);
-       INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk);
        INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
                          cfg80211_dfs_channels_update_work);
 #ifdef CONFIG_CFG80211_WEXT
@@ -837,6 +834,9 @@ int wiphy_register(struct wiphy *wiphy)
                        sband->channels[i].orig_mpwr =
                                sband->channels[i].max_power;
                        sband->channels[i].band = band;
+
+                       if (WARN_ON(sband->channels[i].freq_offset >= 1000))
+                               return -EINVAL;
                }
 
                for (i = 0; i < sband->n_iftype_data; i++) {
@@ -1030,7 +1030,6 @@ void wiphy_unregister(struct wiphy *wiphy)
        cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
        flush_work(&rdev->destroy_work);
        flush_work(&rdev->sched_scan_stop_wk);
-       flush_work(&rdev->mlme_unreg_wk);
        flush_work(&rdev->propagate_radar_detect_wk);
        flush_work(&rdev->propagate_cac_done_wk);
 
@@ -1094,6 +1093,7 @@ static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync)
        rdev->devlist_generation++;
 
        cfg80211_mlme_purge_registrations(wdev);
+       flush_work(&wdev->mgmt_registrations_update_wk);
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_P2P_DEVICE:
@@ -1238,6 +1238,8 @@ void cfg80211_init_wdev(struct cfg80211_registered_device *rdev,
        spin_lock_init(&wdev->event_lock);
        INIT_LIST_HEAD(&wdev->mgmt_registrations);
        spin_lock_init(&wdev->mgmt_registrations_lock);
+       INIT_WORK(&wdev->mgmt_registrations_update_wk,
+                 cfg80211_mgmt_registrations_update_wk);
        INIT_LIST_HEAD(&wdev->pmsr_list);
        spin_lock_init(&wdev->pmsr_lock);
        INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
index bb897a803ffe769771135793503584abb648b90a..639d418965734a9f2a235d55314256768a5262a7 100644 (file)
@@ -60,10 +60,6 @@ struct cfg80211_registered_device {
        struct list_head beacon_registrations;
        spinlock_t beacon_registrations_lock;
 
-       struct list_head mlme_unreg;
-       spinlock_t mlme_unreg_lock;
-       struct work_struct mlme_unreg_wk;
-
        /* protected by RTNL only */
        int num_running_ifaces;
        int num_running_monitor_ifaces;
@@ -385,8 +381,9 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                        struct net_device *dev);
 int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
                                u16 frame_type, const u8 *match_data,
-                               int match_len, struct netlink_ext_ack *extack);
-void cfg80211_mlme_unreg_wk(struct work_struct *wk);
+                               int match_len, bool multicast_rx,
+                               struct netlink_ext_ack *extack);
+void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk);
 void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
index e4805a3bd310410df216e61ce7c8adf7edcc619b..409497a3527db517997c55bf849e92c4f93132fe 100644 (file)
@@ -426,58 +426,62 @@ struct cfg80211_mgmt_registration {
 
        __le16 frame_type;
 
+       bool multicast_rx;
+
        u8 match[];
 };
 
-static void
-cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev)
+static void cfg80211_mgmt_registrations_update(struct wireless_dev *wdev)
 {
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       struct wireless_dev *tmp;
        struct cfg80211_mgmt_registration *reg;
+       struct mgmt_frame_regs upd = {};
 
        ASSERT_RTNL();
 
-       spin_lock_bh(&rdev->mlme_unreg_lock);
-       while ((reg = list_first_entry_or_null(&rdev->mlme_unreg,
-                                              struct cfg80211_mgmt_registration,
-                                              list))) {
-               list_del(&reg->list);
-               spin_unlock_bh(&rdev->mlme_unreg_lock);
+       rcu_read_lock();
+       list_for_each_entry_rcu(tmp, &rdev->wiphy.wdev_list, list) {
+               list_for_each_entry_rcu(reg, &tmp->mgmt_registrations, list) {
+                       u32 mask = BIT(le16_to_cpu(reg->frame_type) >> 4);
+                       u32 mcast_mask = 0;
 
-               if (rdev->ops->mgmt_frame_register) {
-                       u16 frame_type = le16_to_cpu(reg->frame_type);
+                       if (reg->multicast_rx)
+                               mcast_mask = mask;
 
-                       rdev_mgmt_frame_register(rdev, reg->wdev,
-                                                frame_type, false);
-               }
+                       upd.global_stypes |= mask;
+                       upd.global_mcast_stypes |= mcast_mask;
 
-               kfree(reg);
-
-               spin_lock_bh(&rdev->mlme_unreg_lock);
+                       if (tmp == wdev) {
+                               upd.interface_stypes |= mask;
+                               upd.interface_mcast_stypes |= mcast_mask;
+                       }
+               }
        }
-       spin_unlock_bh(&rdev->mlme_unreg_lock);
+       rcu_read_unlock();
+
+       rdev_update_mgmt_frame_registrations(rdev, wdev, &upd);
 }
 
-void cfg80211_mlme_unreg_wk(struct work_struct *wk)
+void cfg80211_mgmt_registrations_update_wk(struct work_struct *wk)
 {
-       struct cfg80211_registered_device *rdev;
-
-       rdev = container_of(wk, struct cfg80211_registered_device,
-                           mlme_unreg_wk);
+       struct wireless_dev *wdev = container_of(wk, struct wireless_dev,
+                                                mgmt_registrations_update_wk);
 
        rtnl_lock();
-       cfg80211_process_mlme_unregistrations(rdev);
+       cfg80211_mgmt_registrations_update(wdev);
        rtnl_unlock();
 }
 
 int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
                                u16 frame_type, const u8 *match_data,
-                               int match_len, struct netlink_ext_ack *extack)
+                               int match_len, bool multicast_rx,
+                               struct netlink_ext_ack *extack)
 {
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct cfg80211_mgmt_registration *reg, *nreg;
        int err = 0;
        u16 mgmt_type;
+       bool update_multicast = false;
 
        if (!wdev->wiphy->mgmt_stypes)
                return -EOPNOTSUPP;
@@ -528,34 +532,39 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
                        continue;
 
                if (memcmp(reg->match, match_data, mlen) == 0) {
+                       if (reg->multicast_rx != multicast_rx) {
+                               update_multicast = true;
+                               reg->multicast_rx = multicast_rx;
+                               break;
+                       }
                        NL_SET_ERR_MSG(extack, "Match already configured");
                        err = -EALREADY;
                        break;
                }
        }
 
-       if (err) {
-               kfree(nreg);
+       if (err)
                goto out;
-       }
 
-       memcpy(nreg->match, match_data, match_len);
-       nreg->match_len = match_len;
-       nreg->nlportid = snd_portid;
-       nreg->frame_type = cpu_to_le16(frame_type);
-       nreg->wdev = wdev;
-       list_add(&nreg->list, &wdev->mgmt_registrations);
+       if (update_multicast) {
+               kfree(nreg);
+       } else {
+               memcpy(nreg->match, match_data, match_len);
+               nreg->match_len = match_len;
+               nreg->nlportid = snd_portid;
+               nreg->frame_type = cpu_to_le16(frame_type);
+               nreg->wdev = wdev;
+               nreg->multicast_rx = multicast_rx;
+               list_add(&nreg->list, &wdev->mgmt_registrations);
+       }
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
 
-       /* process all unregistrations to avoid driver confusion */
-       cfg80211_process_mlme_unregistrations(rdev);
-
-       if (rdev->ops->mgmt_frame_register)
-               rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
+       cfg80211_mgmt_registrations_update(wdev);
 
        return 0;
 
  out:
+       kfree(nreg);
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
 
        return err;
@@ -574,11 +583,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
                        continue;
 
                list_del(&reg->list);
-               spin_lock(&rdev->mlme_unreg_lock);
-               list_add_tail(&reg->list, &rdev->mlme_unreg);
-               spin_unlock(&rdev->mlme_unreg_lock);
+               kfree(reg);
 
-               schedule_work(&rdev->mlme_unreg_wk);
+               schedule_work(&wdev->mgmt_registrations_update_wk);
        }
 
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
@@ -594,15 +601,16 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
 
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       struct cfg80211_mgmt_registration *reg, *tmp;
 
        spin_lock_bh(&wdev->mgmt_registrations_lock);
-       spin_lock(&rdev->mlme_unreg_lock);
-       list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg);
-       spin_unlock(&rdev->mlme_unreg_lock);
+       list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
+               list_del(&reg->list);
+               kfree(reg);
+       }
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
 
-       cfg80211_process_mlme_unregistrations(rdev);
+       cfg80211_mgmt_registrations_update(wdev);
 }
 
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
index 519414468b5d43f25f535996e2dd04134167474e..fa66d5b6f5575f375aee1097c8bc83fb8f6b6b54 100644 (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_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
        [NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
+       [NL80211_ATTR_RECEIVE_MULTICAST] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -3860,14 +3861,25 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        };
        void *hdr;
        struct sk_buff *msg;
+       bool bigtk_support = false;
+
+       if (wiphy_ext_feature_isset(&rdev->wiphy,
+                                   NL80211_EXT_FEATURE_BEACON_PROTECTION))
+               bigtk_support = true;
+
+       if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
+            dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
+           wiphy_ext_feature_isset(&rdev->wiphy,
+                                   NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
+               bigtk_support = true;
 
        if (info->attrs[NL80211_ATTR_KEY_IDX]) {
                key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-               if (key_idx > 5 &&
-                   !wiphy_ext_feature_isset(
-                           &rdev->wiphy,
-                           NL80211_EXT_FEATURE_BEACON_PROTECTION))
+
+               if (key_idx >= 6 && key_idx <= 7 && !bigtk_support) {
+                       GENL_SET_ERR_MSG(info, "BIGTK not supported");
                        return -EINVAL;
+               }
        }
 
        if (info->attrs[NL80211_ATTR_MAC])
@@ -4679,6 +4691,8 @@ static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
                        params->ht_required = true;
                if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_VHT_PHY)
                        params->vht_required = true;
+               if (rates[2 + i] == BSS_MEMBERSHIP_SELECTOR_HE_PHY)
+                       params->he_required = true;
        }
 }
 
@@ -10726,9 +10740,18 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->mgmt_tx)
                return -EOPNOTSUPP;
 
+       if (info->attrs[NL80211_ATTR_RECEIVE_MULTICAST] &&
+           !wiphy_ext_feature_isset(&rdev->wiphy,
+                                    NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS)) {
+               GENL_SET_ERR_MSG(info,
+                                "multicast RX registrations are not supported");
+               return -EOPNOTSUPP;
+       }
+
        return cfg80211_mlme_register_mgmt(wdev, info->snd_portid, frame_type,
                                           nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
                                           nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]),
+                                          info->attrs[NL80211_ATTR_RECEIVE_MULTICAST],
                                           info->extack);
 }
 
@@ -15495,10 +15518,19 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
        if (WARN_ON(len < 2))
                return;
 
-       if (ieee80211_is_deauth(mgmt->frame_control))
+       if (ieee80211_is_deauth(mgmt->frame_control)) {
                cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
-       else
+       } else if (ieee80211_is_disassoc(mgmt->frame_control)) {
                cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
+       } else if (ieee80211_is_beacon(mgmt->frame_control)) {
+               if (wdev->unprot_beacon_reported &&
+                   elapsed_jiffies_msecs(wdev->unprot_beacon_reported) < 10000)
+                       return;
+               cmd = NL80211_CMD_UNPROT_BEACON;
+               wdev->unprot_beacon_reported = jiffies;
+       } else {
+               return;
+       }
 
        trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
        nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1,
index 99462f0c4e08f1bb924e90d2df142701b3329d54..df5142e86c4f39ebcca6a9011cf57f0f8fa959e0 100644 (file)
@@ -819,13 +819,16 @@ rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
 }
 
 static inline void
-rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev,
-                        struct wireless_dev *wdev, u16 frame_type, bool reg)
+rdev_update_mgmt_frame_registrations(struct cfg80211_registered_device *rdev,
+                                    struct wireless_dev *wdev,
+                                    struct mgmt_frame_regs *upd)
 {
        might_sleep();
 
-       trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
-       rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg);
+       trace_rdev_update_mgmt_frame_registrations(&rdev->wiphy, wdev, upd);
+       if (rdev->ops->update_mgmt_frame_registrations)
+               rdev->ops->update_mgmt_frame_registrations(&rdev->wiphy, wdev,
+                                                          upd);
        trace_rdev_return_void(&rdev->wiphy);
 }
 
index d476d4da0d096b6c77d30991cc9a9ecb3732e08c..0d74a31ef0ab4e1d077ecefc2a03750729987c00 100644 (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_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;
 
        max_bandwidth_khz = freq_range->max_bandwidth_khz;
+       center_freq_khz = ieee80211_channel_to_khz(chan);
        /* Check if auto calculation requested */
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
        /* If we get a reg_rule we can assume that at least 5Mhz fit */
        if (!cfg80211_does_bw_fit_range(freq_range,
-                                       MHZ_TO_KHZ(chan->center_freq),
+                                       center_freq_khz,
                                        MHZ_TO_KHZ(10)))
                bw_flags |= IEEE80211_CHAN_NO_10MHZ;
        if (!cfg80211_does_bw_fit_range(freq_range,
-                                       MHZ_TO_KHZ(chan->center_freq),
+                                       center_freq_khz,
                                        MHZ_TO_KHZ(20)))
                bw_flags |= IEEE80211_CHAN_NO_20MHZ;
 
@@ -1710,7 +1711,7 @@ static void handle_channel(struct wiphy *wiphy,
 
        flags = chan->orig_flags;
 
-       reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));
+       reg_rule = freq_reg_info(wiphy, ieee80211_channel_to_khz(chan));
        if (IS_ERR(reg_rule)) {
                /*
                 * We will disable all channels that do not match our
@@ -1729,13 +1730,13 @@ static void handle_channel(struct wiphy *wiphy,
                if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
                    request_wiphy && request_wiphy == wiphy &&
                    request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
-                       pr_debug("Disabling freq %d MHz for good\n",
-                                chan->center_freq);
+                       pr_debug("Disabling freq %d.%03d MHz for good\n",
+                                chan->center_freq, chan->freq_offset);
                        chan->orig_flags |= IEEE80211_CHAN_DISABLED;
                        chan->flags = chan->orig_flags;
                } else {
-                       pr_debug("Disabling freq %d MHz\n",
-                                chan->center_freq);
+                       pr_debug("Disabling freq %d.%03d MHz\n",
+                                chan->center_freq, chan->freq_offset);
                        chan->flags |= IEEE80211_CHAN_DISABLED;
                }
                return;
@@ -1936,7 +1937,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
        sband = wiphy->bands[reg_beacon->chan.band];
        chan = &sband->channels[chan_idx];
 
-       if (likely(chan->center_freq != reg_beacon->chan.center_freq))
+       if (likely(!ieee80211_channel_equal(chan, &reg_beacon->chan)))
                return;
 
        if (chan->beacon_found)
@@ -2269,18 +2270,18 @@ static void handle_channel_custom(struct wiphy *wiphy,
        u32 bw_flags = 0;
        const struct ieee80211_reg_rule *reg_rule = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
-       u32 bw;
+       u32 bw, center_freq_khz;
 
+       center_freq_khz = ieee80211_channel_to_khz(chan);
        for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
-               reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq),
-                                             regd, bw);
+               reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw);
                if (!IS_ERR(reg_rule))
                        break;
        }
 
        if (IS_ERR_OR_NULL(reg_rule)) {
-               pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
-                        chan->center_freq);
+               pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n",
+                        chan->center_freq, chan->freq_offset);
                if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
                        chan->flags |= IEEE80211_CHAN_DISABLED;
                } else {
@@ -3337,8 +3338,8 @@ static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
        struct reg_beacon *pending_beacon;
 
        list_for_each_entry(pending_beacon, &reg_pending_beacons, list)
-               if (beacon_chan->center_freq ==
-                   pending_beacon->chan.center_freq)
+               if (ieee80211_channel_equal(beacon_chan,
+                                           &pending_beacon->chan))
                        return true;
        return false;
 }
@@ -3367,9 +3368,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
        if (!reg_beacon)
                return -ENOMEM;
 
-       pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
-                beacon_chan->center_freq,
-                ieee80211_frequency_to_channel(beacon_chan->center_freq),
+       pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n",
+                beacon_chan->center_freq, beacon_chan->freq_offset,
+                ieee80211_freq_khz_to_channel(
+                        ieee80211_channel_to_khz(beacon_chan)),
                 wiphy_name(wiphy));
 
        memcpy(&reg_beacon->chan, beacon_chan,
index 4000382aef4896f306e218fa34500b79d703004a..74ea4cfb39fbde4231f7b9b76071c3dd2c1ad5ac 100644 (file)
@@ -1322,8 +1322,8 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
                return channel;
        }
 
-       freq = ieee80211_channel_to_frequency(channel_number, channel->band);
-       alt_channel = ieee80211_get_channel(wiphy, freq);
+       freq = ieee80211_channel_to_freq_khz(channel_number, channel->band);
+       alt_channel = ieee80211_get_channel_khz(wiphy, freq);
        if (!alt_channel) {
                if (channel->band == NL80211_BAND_2GHZ) {
                        /*
index ac3e60aa1fc8a786859657910ec439e220f146b5..3554c0d951f4a0ac9ac1b0dc738e2c1f6a4f5ec2 100644 (file)
@@ -694,6 +694,7 @@ void __cfg80211_connect_result(struct net_device *dev,
                return;
        }
 
+       wdev->unprot_beacon_reported = 0;
        nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
                                    GFP_KERNEL);
 
@@ -921,6 +922,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
        cfg80211_hold_bss(bss_from_pub(info->bss));
        wdev->current_bss = bss_from_pub(info->bss);
 
+       wdev->unprot_beacon_reported = 0;
        nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
                            wdev->netdev, info, GFP_KERNEL);
 
index 839df54cee21af43110c6aa6c90da92de7a35c0d..53c887ea67c78c216dec81892c249b4e083b5818 100644 (file)
        } while (0)
 
 #define CHAN_ENTRY __field(enum nl80211_band, band) \
-                  __field(u32, center_freq)
+                  __field(u32, center_freq)            \
+                  __field(u16, freq_offset)
 #define CHAN_ASSIGN(chan)                                        \
        do {                                                      \
                if (chan) {                                       \
                        __entry->band = chan->band;               \
                        __entry->center_freq = chan->center_freq; \
+                       __entry->freq_offset = chan->freq_offset; \
                } else {                                          \
                        __entry->band = 0;                        \
                        __entry->center_freq = 0;                 \
+                       __entry->freq_offset = 0;                 \
                }                                                 \
        } while (0)
-#define CHAN_PR_FMT "band: %d, freq: %u"
-#define CHAN_PR_ARG __entry->band, __entry->center_freq
+#define CHAN_PR_FMT "band: %d, freq: %u.%03u"
+#define CHAN_PR_ARG __entry->band, __entry->center_freq, __entry->freq_offset
 
 #define CHAN_DEF_ENTRY __field(enum nl80211_band, band)                \
                       __field(u32, control_freq)                       \
+                      __field(u32, freq_offset)                        \
                       __field(u32, width)                              \
                       __field(u32, center_freq1)                       \
+                      __field(u32, freq1_offset)                       \
                       __field(u32, center_freq2)
 #define CHAN_DEF_ASSIGN(chandef)                                       \
        do {                                                            \
                        __entry->band = (chandef)->chan->band;          \
                        __entry->control_freq =                         \
                                (chandef)->chan->center_freq;           \
+                       __entry->freq_offset =                          \
+                               (chandef)->chan->freq_offset;           \
                        __entry->width = (chandef)->width;              \
                        __entry->center_freq1 = (chandef)->center_freq1;\
+                       __entry->freq1_offset = (chandef)->freq1_offset;\
                        __entry->center_freq2 = (chandef)->center_freq2;\
                } else {                                                \
                        __entry->band = 0;                              \
                        __entry->control_freq = 0;                      \
+                       __entry->freq_offset = 0;                       \
                        __entry->width = 0;                             \
                        __entry->center_freq1 = 0;                      \
+                       __entry->freq1_offset = 0;                      \
                        __entry->center_freq2 = 0;                      \
                }                                                       \
        } while (0)
 #define CHAN_DEF_PR_FMT                                                        \
-       "band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
+       "band: %d, control freq: %u.%03u, width: %d, cf1: %u.%03u, cf2: %u"
 #define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq,          \
-                       __entry->width, __entry->center_freq1,          \
+                       __entry->freq_offset, __entry->width,           \
+                       __entry->center_freq1, __entry->freq1_offset,   \
                        __entry->center_freq2
 
 #define SINFO_ENTRY __field(int, generation)       \
@@ -1582,25 +1593,25 @@ TRACE_EVENT(rdev_set_bitrate_mask,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
 );
 
-TRACE_EVENT(rdev_mgmt_frame_register,
+TRACE_EVENT(rdev_update_mgmt_frame_registrations,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
-                u16 frame_type, bool reg),
-       TP_ARGS(wiphy, wdev, frame_type, reg),
+                struct mgmt_frame_regs *upd),
+       TP_ARGS(wiphy, wdev, upd),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                WDEV_ENTRY
-               __field(u16, frame_type)
-               __field(bool, reg)
+               __field(u16, global_stypes)
+               __field(u16, interface_stypes)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                WDEV_ASSIGN;
-               __entry->frame_type = frame_type;
-               __entry->reg = reg;
+               __entry->global_stypes = upd->global_stypes;
+               __entry->interface_stypes = upd->interface_stypes;
        ),
-       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ",
-                 WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type,
-                 __entry->reg ? "true" : "false")
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", global: 0x%.2x, intf: 0x%.2x",
+                 WIPHY_PR_ARG, WDEV_PR_ARG,
+                 __entry->global_stypes, __entry->interface_stypes)
 );
 
 TRACE_EVENT(rdev_return_int_tx_rx,
index 6590efbbcbb9d4623632ed39b0e072ca4f8e3bb0..df75e58eca5dfa846bffbb3c838eb7fdd7f23c72 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright 2017      Intel Deutschland GmbH
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
  */
 #include <linux/export.h>
 #include <linux/bitops.h>
@@ -72,7 +72,7 @@ u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
 }
 EXPORT_SYMBOL(ieee80211_mandatory_rates);
 
-int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
+u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
 {
        /* see 802.11 17.3.8.3.2 and Annex J
         * there are overlapping channel numbers in 5GHz and 2GHz bands */
@@ -81,15 +81,15 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
        switch (band) {
        case NL80211_BAND_2GHZ:
                if (chan == 14)
-                       return 2484;
+                       return MHZ_TO_KHZ(2484);
                else if (chan < 14)
-                       return 2407 + chan * 5;
+                       return MHZ_TO_KHZ(2407 + chan * 5);
                break;
        case NL80211_BAND_5GHZ:
                if (chan >= 182 && chan <= 196)
-                       return 4000 + chan * 5;
+                       return MHZ_TO_KHZ(4000 + chan * 5);
                else
-                       return 5000 + chan * 5;
+                       return MHZ_TO_KHZ(5000 + chan * 5);
                break;
        case NL80211_BAND_6GHZ:
                /* see 802.11ax D4.1 27.3.22.2 */
@@ -98,17 +98,20 @@ int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
                break;
        case NL80211_BAND_60GHZ:
                if (chan < 7)
-                       return 56160 + chan * 2160;
+                       return MHZ_TO_KHZ(56160 + chan * 2160);
                break;
        default:
                ;
        }
        return 0; /* not supported */
 }
-EXPORT_SYMBOL(ieee80211_channel_to_frequency);
+EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
 
-int ieee80211_frequency_to_channel(int freq)
+int ieee80211_freq_khz_to_channel(u32 freq)
 {
+       /* TODO: just handle MHz for now */
+       freq = KHZ_TO_MHZ(freq);
+
        /* see 802.11 17.3.8.3.2 and Annex J */
        if (freq == 2484)
                return 14;
@@ -126,9 +129,10 @@ int ieee80211_frequency_to_channel(int freq)
        else
                return 0;
 }
-EXPORT_SYMBOL(ieee80211_frequency_to_channel);
+EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
 
-struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
+struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
+                                                   u32 freq)
 {
        enum nl80211_band band;
        struct ieee80211_supported_band *sband;
@@ -141,14 +145,16 @@ struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
                        continue;
 
                for (i = 0; i < sband->n_channels; i++) {
-                       if (sband->channels[i].center_freq == freq)
-                               return &sband->channels[i];
+                       struct ieee80211_channel *chan = &sband->channels[i];
+
+                       if (ieee80211_channel_to_khz(chan) == freq)
+                               return chan;
                }
        }
 
        return NULL;
 }
-EXPORT_SYMBOL(ieee80211_get_channel);
+EXPORT_SYMBOL(ieee80211_get_channel_khz);
 
 static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
 {
@@ -2030,10 +2036,10 @@ EXPORT_SYMBOL(cfg80211_send_layer2_update);
 
 int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
                              enum ieee80211_vht_chanwidth bw,
-                             int mcs, bool ext_nss_bw_capable)
+                             int mcs, bool ext_nss_bw_capable,
+                             unsigned int max_vht_nss)
 {
        u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map);
-       int max_vht_nss = 0;
        int ext_nss_bw;
        int supp_width;
        int i, mcs_encoding;
@@ -2041,7 +2047,7 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
        if (map == 0xffff)
                return 0;
 
-       if (WARN_ON(mcs > 9))
+       if (WARN_ON(mcs > 9 || max_vht_nss > 8))
                return 0;
        if (mcs <= 7)
                mcs_encoding = 0;
@@ -2050,16 +2056,18 @@ int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
        else
                mcs_encoding = 2;
 
-       /* find max_vht_nss for the given MCS */
-       for (i = 7; i >= 0; i--) {
-               int supp = (map >> (2 * i)) & 3;
+       if (!max_vht_nss) {
+               /* find max_vht_nss for the given MCS */
+               for (i = 7; i >= 0; i--) {
+                       int supp = (map >> (2 * i)) & 3;
 
-               if (supp == 3)
-                       continue;
+                       if (supp == 3)
+                               continue;
 
-               if (supp >= mcs_encoding) {
-                       max_vht_nss = i + 1;
-                       break;
+                       if (supp >= mcs_encoding) {
+                               max_vht_nss = i + 1;
+                               break;
+                       }
                }
        }