Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac802...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 12 Feb 2014 20:24:14 +0000 (15:24 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 12 Feb 2014 20:24:14 +0000 (15:24 -0500)
70 files changed:
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/wcn36xx/txrx.c
drivers/net/wireless/brcm80211/brcmfmac/fwil.c
drivers/net/wireless/brcm80211/brcmfmac/fwil.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/iwlegacy/3945-rs.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rtlwifi/rc.c
drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/ieee80211_radiotap.h
include/net/mac80211.h
include/uapi/linux/nl80211.h
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/cfg.h
net/mac80211/chan.c
net/mac80211/debugfs_sta.c
net/mac80211/ht.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/rate.c
net/mac80211/rate.h
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel.h
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_pid_algo.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac80211/wpa.c
net/rfkill/core.c
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/trace.h
net/wireless/util.c

index 74f45fa6f428de9d297c2af388ab1acb15247b60..27f20e0510f7a1dc0574d746f90e3bcaa624f99c 100644 (file)
@@ -204,7 +204,7 @@ static void process_rx_rates(struct ath10k *ar, struct htt_rx_info *info,
                        break;
                /* 80MHZ */
                case 2:
-                       status->flag |= RX_FLAG_80MHZ;
+                       status->vht_flag |= RX_VHT_FLAG_80MHZ;
                }
 
                status->flag |= RX_FLAG_VHT;
@@ -266,7 +266,7 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
                   status->flag & RX_FLAG_HT ? "ht" : "",
                   status->flag & RX_FLAG_VHT ? "vht" : "",
                   status->flag & RX_FLAG_40MHZ ? "40" : "",
-                  status->flag & RX_FLAG_80MHZ ? "80" : "",
+                  status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
                   status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
                   status->rate_idx,
                   status->vht_nss,
index fd4c89df67e1658ae404686a911fc62607cee1cd..c2c6f460495859ae3517c4f20daa2c15caebdde0 100644 (file)
@@ -790,7 +790,7 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
        if (nw_type & ADHOC_NETWORK) {
                ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "ad-hoc %s selected\n",
                           nw_type & ADHOC_CREATOR ? "creator" : "joiner");
-               cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
+               cfg80211_ibss_joined(vif->ndev, bssid, chan, GFP_KERNEL);
                cfg80211_put_bss(ar->wiphy, bss);
                return;
        }
@@ -861,13 +861,9 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
        }
 
        if (vif->nw_type & ADHOC_NETWORK) {
-               if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC) {
+               if (vif->wdev.iftype != NL80211_IFTYPE_ADHOC)
                        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                                   "%s: ath6k not in ibss mode\n", __func__);
-                       return;
-               }
-               memset(bssid, 0, ETH_ALEN);
-               cfg80211_ibss_joined(vif->ndev, bssid, GFP_KERNEL);
                return;
        }
 
@@ -3256,6 +3252,15 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        struct ath6kl_vif *vif = netdev_priv(dev);
        u16 interval;
        int ret, rssi_thold;
+       int n_match_sets = request->n_match_sets;
+
+       /*
+        * If there's a matchset w/o an SSID, then assume it's just for
+        * the RSSI (nothing else is currently supported) and ignore it.
+        * The device only supports a global RSSI filter that we set below.
+        */
+       if (n_match_sets == 1 && !request->match_sets[0].ssid.ssid_len)
+               n_match_sets = 0;
 
        if (ar->state != ATH6KL_STATE_ON)
                return -EIO;
@@ -3268,11 +3273,11 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
                                      request->n_ssids,
                                      request->match_sets,
-                                     request->n_match_sets);
+                                     n_match_sets);
        if (ret < 0)
                return ret;
 
-       if (!request->n_match_sets) {
+       if (!n_match_sets) {
                ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
                                               ALL_BSS_FILTER, 0);
                if (ret < 0)
@@ -3286,12 +3291,12 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
 
        if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
                     ar->fw_capabilities)) {
-               if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
+               if (request->min_rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
                        rssi_thold = 0;
-               else if (request->rssi_thold < -127)
+               else if (request->min_rssi_thold < -127)
                        rssi_thold = -127;
                else
-                       rssi_thold = request->rssi_thold;
+                       rssi_thold = request->min_rssi_thold;
 
                ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
                                                     rssi_thold);
index d829bb62a3fc6d9e94ae867b2a675530ea4d1d7a..7b5afee141dacecab4af81b90d543b3a57d822bf 100644 (file)
@@ -1466,8 +1466,7 @@ static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta,
        kfree(rate_priv);
 }
 
-static struct rate_control_ops ath_rate_ops = {
-       .module = NULL,
+static const struct rate_control_ops ath_rate_ops = {
        .name = "ath9k_rate_control",
        .tx_status = ath_tx_status,
        .get_rate = ath_get_rate,
index b2b60e30caaf8492886467e6c8a14b32b6f95467..6846f858ef62323556cf5b5dfbef60a25b639be3 100644 (file)
@@ -57,8 +57,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
                       RX_FLAG_MMIC_STRIPPED |
                       RX_FLAG_DECRYPTED;
 
-       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x status->vendor_radiotap_len=%x\n",
-                   status.flag,  status.vendor_radiotap_len);
+       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
 
        memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
 
index 22adbe311d206df979a592419d7d247280474ec6..59a5af5bf994d88b3e4f969c8e0633de3bd57d87 100644 (file)
@@ -124,7 +124,8 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
 }
 
 static u32
-brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
+brcmf_create_iovar(char *name, const char *data, u32 datalen,
+                  char *buf, u32 buflen)
 {
        u32 len;
 
@@ -144,7 +145,7 @@ brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
 
 
 s32
-brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
+brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
                         u32 len)
 {
        struct brcmf_pub *drvr = ifp->drvr;
index 77eae86e55c23318e439fa23118f3d10e4b33788..a30be683f4a15eff78c0fa2a5133ed176b4962a0 100644 (file)
@@ -83,7 +83,7 @@ s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
 s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);
 s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data);
 
-s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
+s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
                             u32 len);
 s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
                             u32 len);
index d7718a5fa2f0323c46458300f417b7dbd6e46b8e..1a80bf19cb8908465f9dd15119493ab1dbd02d96 100644 (file)
@@ -351,13 +351,11 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
  * triples, returning a pointer to the substring whose first element
  * matches tag
  */
-struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key)
 {
-       struct brcmf_tlv *elt;
-       int totlen;
-
-       elt = (struct brcmf_tlv *)buf;
-       totlen = buflen;
+       const struct brcmf_tlv *elt = buf;
+       int totlen = buflen;
 
        /* find tagged parameter */
        while (totlen >= TLV_HDR_LEN) {
@@ -378,8 +376,8 @@ struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
  * not update the tlvs buffer pointer/length.
  */
 static bool
-brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
-                u8 *oui, u32 oui_len, u8 type)
+brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
+                const u8 *oui, u32 oui_len, u8 type)
 {
        /* If the contents match the OUI and the type */
        if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
@@ -401,12 +399,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
 }
 
 static struct brcmf_vs_tlv *
-brcmf_find_wpaie(u8 *parse, u32 len)
+brcmf_find_wpaie(const u8 *parse, u32 len)
 {
-       struct brcmf_tlv *ie;
+       const struct brcmf_tlv *ie;
 
        while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
-               if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
+               if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
                                     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
                        return (struct brcmf_vs_tlv *)ie;
        }
@@ -414,9 +412,9 @@ brcmf_find_wpaie(u8 *parse, u32 len)
 }
 
 static struct brcmf_vs_tlv *
-brcmf_find_wpsie(u8 *parse, u32 len)
+brcmf_find_wpsie(const u8 *parse, u32 len)
 {
-       struct brcmf_tlv *ie;
+       const struct brcmf_tlv *ie;
 
        while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
                if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
@@ -1562,9 +1560,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
        struct ieee80211_channel *chan = sme->channel;
        struct brcmf_join_params join_params;
        size_t join_params_size;
-       struct brcmf_tlv *rsn_ie;
-       struct brcmf_vs_tlv *wpa_ie;
-       void *ie;
+       const struct brcmf_tlv *rsn_ie;
+       const struct brcmf_vs_tlv *wpa_ie;
+       const void *ie;
        u32 ie_len;
        struct brcmf_ext_join_params_le *ext_join_params;
        u16 chanspec;
@@ -1591,7 +1589,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                        ie_len = wpa_ie->len + TLV_HDR_LEN;
                } else {
                        /* find the RSN_IE */
-                       rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+                       rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
+                                                 sme->ie_len,
                                                  WLAN_EID_RSN);
                        if (rsn_ie) {
                                ie = rsn_ie;
@@ -2455,7 +2454,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
        struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
        struct brcmf_bss_info_le *bi;
        struct brcmf_ssid *ssid;
-       struct brcmf_tlv *tim;
+       const struct brcmf_tlv *tim;
        u16 beacon_interval;
        u8 dtim_period;
        size_t ie_len;
@@ -3220,8 +3219,9 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
 }
 
 static s32
-brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
-                    bool is_rsn_ie)
+brcmf_configure_wpaie(struct net_device *ndev,
+                     const struct brcmf_vs_tlv *wpa_ie,
+                     bool is_rsn_ie)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        u32 auth = 0; /* d11 open authentication */
@@ -3707,11 +3707,11 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        s32 ie_offset;
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_tlv *ssid_ie;
+       const struct brcmf_tlv *ssid_ie;
        struct brcmf_ssid_le ssid_le;
        s32 err = -EPERM;
-       struct brcmf_tlv *rsn_ie;
-       struct brcmf_vs_tlv *wpa_ie;
+       const struct brcmf_tlv *rsn_ie;
+       const struct brcmf_vs_tlv *wpa_ie;
        struct brcmf_join_params join_params;
        enum nl80211_iftype dev_role;
        struct brcmf_fil_bss_enable_le bss_enable;
@@ -4658,6 +4658,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
        struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        struct net_device *ndev = ifp->ndev;
        struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+       struct ieee80211_channel *chan;
        s32 err = 0;
 
        if (ifp->vif->mode == WL_MODE_AP) {
@@ -4665,9 +4666,10 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
        } else if (brcmf_is_linkup(e)) {
                brcmf_dbg(CONN, "Linkup\n");
                if (brcmf_is_ibssmode(ifp->vif)) {
+                       chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
                        memcpy(profile->bssid, e->addr, ETH_ALEN);
                        wl_inform_ibss(cfg, ndev, e->addr);
-                       cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+                       cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
                        clear_bit(BRCMF_VIF_STATUS_CONNECTING,
                                  &ifp->vif->sme_state);
                        set_bit(BRCMF_VIF_STATUS_CONNECTED,
index 2dc6a074e8ede14c4d3709a2d899c390e1bd421c..254feed2860e968d6dd52860c7cc66d23e5d0baf 100644 (file)
@@ -491,7 +491,8 @@ void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
                          const u8 *vndr_ie_buf, u32 vndr_ie_len);
 s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
-struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
+const struct brcmf_tlv *
+brcmf_parse_tlvs(const void *buf, int buflen, uint key);
 u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
                        struct ieee80211_channel *ch);
 u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
index 9a45f6f626f69633c938bd386242cdacff6496e7..76b0729ade17ee2d18cc42df934f286762c2c155 100644 (file)
@@ -891,8 +891,7 @@ il3945_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
 {
 }
 
-static struct rate_control_ops rs_ops = {
-       .module = NULL,
+static const struct rate_control_ops rs_ops = {
        .name = RS_NAME,
        .tx_status = il3945_rs_tx_status,
        .get_rate = il3945_rs_get_rate,
index 4d5e33259ca894d66fe2edc997b8d3ed6580467b..eaaeea19d8c5bcc99d887ee7b3fd9c592b897045 100644 (file)
@@ -2807,8 +2807,7 @@ il4965_rs_rate_init_stub(void *il_r, struct ieee80211_supported_band *sband,
 {
 }
 
-static struct rate_control_ops rs_4965_ops = {
-       .module = NULL,
+static const struct rate_control_ops rs_4965_ops = {
        .name = IL4965_RS_NAME,
        .tx_status = il4965_rs_tx_status,
        .get_rate = il4965_rs_get_rate,
index 5e232b925455417d02c06592b830ba5c06553fbf..aa773a2da4ab877f6b5876a28024a6c2e23ffa9b 100644 (file)
@@ -3318,8 +3318,8 @@ static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sba
                              struct ieee80211_sta *sta, void *priv_sta)
 {
 }
-static struct rate_control_ops rs_ops = {
-       .module = NULL,
+
+static const struct rate_control_ops rs_ops = {
        .name = RS_NAME,
        .tx_status = rs_tx_status,
        .get_rate = rs_get_rate,
index 3b73241db24d1809e87df0a7ad2d13f8dbeceb2a..32bb8075121cdb4eeaaab80ad926fabf5bc7b620 100644 (file)
@@ -2814,8 +2814,8 @@ static void rs_rate_init_stub(void *mvm_r,
                              struct ieee80211_sta *sta, void *mvm_sta)
 {
 }
-static struct rate_control_ops rs_mvm_ops = {
-       .module = NULL,
+
+static const struct rate_control_ops rs_mvm_ops = {
        .name = RS_NAME,
        .tx_status = rs_tx_status,
        .get_rate = rs_get_rate,
index ef727df84da7279f73e429f91c74a91224d635ea..fa3c1393e1032e05170389ae61e65c107fa129a2 100644 (file)
@@ -358,10 +358,10 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                rx_status.flag |= RX_FLAG_40MHZ;
                break;
        case RATE_MCS_CHAN_WIDTH_80:
-               rx_status.flag |= RX_FLAG_80MHZ;
+               rx_status.vht_flag |= RX_VHT_FLAG_80MHZ;
                break;
        case RATE_MCS_CHAN_WIDTH_160:
-               rx_status.flag |= RX_FLAG_160MHZ;
+               rx_status.vht_flag |= RX_VHT_FLAG_160MHZ;
                break;
        }
        if (rate_n_flags & RATE_MCS_SGI_MSK)
index a827a13f98734a27a552faf8645fa737471d641f..bf4e773c6f468d6d51ab1f332295d4a265287d8a 100644 (file)
@@ -603,6 +603,9 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
         * config match list.
         */
        for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
+               /* skip empty SSID matchsets */
+               if (!req->match_sets[i].ssid.ssid_len)
+                       continue;
                scan->direct_scan[i].id = WLAN_EID_SSID;
                scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
                memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
index 32f75007a825be6c24b6195d35a9f4e31d590961..2d72a6b4b93e927b37c0e7ee2c5d316c475b3a47 100644 (file)
@@ -1766,7 +1766,8 @@ static void lbs_join_post(struct lbs_private *priv,
        memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
        priv->wdev->ssid_len = params->ssid_len;
 
-       cfg80211_ibss_joined(priv->dev, bssid, GFP_KERNEL);
+       cfg80211_ibss_joined(priv->dev, bssid, params->chandef.chan,
+                            GFP_KERNEL);
 
        /* TODO: consider doing this at MACREG_INT_CODE_LINK_SENSED time */
        priv->connect_status = LBS_CONNECTED;
index 69d4c3179d042159122911539f41619ae7e71597..f7e3562542feae86fdf4ad62cc06a86aac47f67b 100644 (file)
@@ -57,6 +57,10 @@ static bool rctbl = false;
 module_param(rctbl, bool, 0444);
 MODULE_PARM_DESC(rctbl, "Handle rate control table");
 
+static bool support_p2p_device = true;
+module_param(support_p2p_device, bool, 0444);
+MODULE_PARM_DESC(support_p2p_device, "Support P2P-Device interface type");
+
 /**
  * enum hwsim_regtest - the type of regulatory tests we offer
  *
@@ -335,7 +339,8 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
 #endif
                                 BIT(NL80211_IFTYPE_AP) |
                                 BIT(NL80211_IFTYPE_P2P_GO) },
-       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
+       /* must be last, see hwsim_if_comb */
+       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }
 };
 
 static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
@@ -343,6 +348,27 @@ static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
 };
 
 static const struct ieee80211_iface_combination hwsim_if_comb[] = {
+       {
+               .limits = hwsim_if_limits,
+               /* remove the last entry which is P2P_DEVICE */
+               .n_limits = ARRAY_SIZE(hwsim_if_limits) - 1,
+               .max_interfaces = 2048,
+               .num_different_channels = 1,
+       },
+       {
+               .limits = hwsim_if_dfs_limits,
+               .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
+               .max_interfaces = 8,
+               .num_different_channels = 1,
+               .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                      BIT(NL80211_CHAN_WIDTH_20) |
+                                      BIT(NL80211_CHAN_WIDTH_40) |
+                                      BIT(NL80211_CHAN_WIDTH_80) |
+                                      BIT(NL80211_CHAN_WIDTH_160),
+       }
+};
+
+static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
        {
                .limits = hwsim_if_limits,
                .n_limits = ARRAY_SIZE(hwsim_if_limits),
@@ -451,7 +477,7 @@ static struct genl_family hwsim_genl_family = {
 
 /* MAC80211_HWSIM netlink policy */
 
-static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
+static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
        [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
        [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY,
@@ -468,6 +494,7 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 },
        [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
        [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
+       [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1035,32 +1062,6 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
                        ack = true;
 
                rx_status.mactime = now + data2->tsf_offset;
-#if 0
-               /*
-                * Don't enable this code by default as the OUI 00:00:00
-                * is registered to Xerox so we shouldn't use it here, it
-                * might find its way into pcap files.
-                * Note that this code requires the headroom in the SKB
-                * that was allocated earlier.
-                */
-               rx_status.vendor_radiotap_oui[0] = 0x00;
-               rx_status.vendor_radiotap_oui[1] = 0x00;
-               rx_status.vendor_radiotap_oui[2] = 0x00;
-               rx_status.vendor_radiotap_subns = 127;
-               /*
-                * Radiotap vendor namespaces can (and should) also be
-                * split into fields by using the standard radiotap
-                * presence bitmap mechanism. Use just BIT(0) here for
-                * the presence bitmap.
-                */
-               rx_status.vendor_radiotap_bitmap = BIT(0);
-               /* We have 8 bytes of (dummy) data */
-               rx_status.vendor_radiotap_len = 8;
-               /* For testing, also require it to be aligned */
-               rx_status.vendor_radiotap_align = 8;
-               /* push the data */
-               memcpy(skb_push(nskb, 8), "ABCDEFGH", 8);
-#endif
 
                memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
                ieee80211_rx_irqsafe(data2->hw, nskb);
@@ -1275,6 +1276,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
 
        mac80211_hwsim_tx_frame(hw, skb,
                                rcu_dereference(vif->chanctx_conf)->def.chan);
+
+       if (vif->csa_active && ieee80211_csa_is_complete(vif))
+               ieee80211_csa_finish(vif);
 }
 
 static enum hrtimer_restart
@@ -1936,7 +1940,7 @@ static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 
 static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                                       const struct ieee80211_regdomain *regd,
-                                      bool reg_strict)
+                                      bool reg_strict, bool p2p_device)
 {
        int err;
        u8 addr[ETH_ALEN];
@@ -2000,8 +2004,15 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                /* For channels > 1 DFS is not allowed */
                hw->wiphy->n_iface_combinations = 1;
                hw->wiphy->iface_combinations = &data->if_combination;
-               data->if_combination = hwsim_if_comb[0];
                data->if_combination.num_different_channels = data->channels;
+               if (p2p_device)
+                       data->if_combination = hwsim_if_comb_p2p_dev[0];
+               else
+                       data->if_combination = hwsim_if_comb[0];
+       } else if (p2p_device) {
+               hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(hwsim_if_comb_p2p_dev);
        } else {
                hw->wiphy->iface_combinations = hwsim_if_comb;
                hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
@@ -2017,8 +2028,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                                     BIT(NL80211_IFTYPE_P2P_CLIENT) |
                                     BIT(NL80211_IFTYPE_P2P_GO) |
                                     BIT(NL80211_IFTYPE_ADHOC) |
-                                    BIT(NL80211_IFTYPE_MESH_POINT) |
-                                    BIT(NL80211_IFTYPE_P2P_DEVICE);
+                                    BIT(NL80211_IFTYPE_MESH_POINT);
+
+       if (p2p_device)
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
 
        hw->flags = IEEE80211_HW_MFP_CAPABLE |
                    IEEE80211_HW_SIGNAL_DBM |
@@ -2027,13 +2040,15 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_WANT_MONITOR_VIF |
                    IEEE80211_HW_QUEUE_CONTROL |
-                   IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+                   IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
+                   IEEE80211_HW_CHANCTX_STA_CSA;
        if (rctbl)
                hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
 
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
                            WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
-                           WIPHY_FLAG_AP_UAPSD;
+                           WIPHY_FLAG_AP_UAPSD |
+                           WIPHY_FLAG_HAS_CHANNEL_SWITCH;
        hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
 
        /* ask mac80211 to reserve space for magic */
@@ -2407,6 +2422,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
        const char *alpha2 = NULL;
        const struct ieee80211_regdomain *regd = NULL;
        bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
+       bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
 
        if (info->attrs[HWSIM_ATTR_CHANNELS])
                chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
@@ -2422,7 +2438,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
                regd = hwsim_world_regdom_custom[idx];
        }
 
-       return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict);
+       return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
+                                          p2p_device);
 }
 
 static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2640,7 +2657,8 @@ static int __init init_mac80211_hwsim(void)
                }
 
                err = mac80211_hwsim_create_radio(channels, reg_alpha2,
-                                                 regd, reg_strict);
+                                                 regd, reg_strict,
+                                                 support_p2p_device);
                if (err < 0)
                        goto out_free_radios;
        }
index 2747cce5a269e46d42d1b3f6f819b59753b8aa8b..6e72996ec8c1f1dae6386a5e9755fa6b3a5041ba 100644 (file)
@@ -107,6 +107,7 @@ enum {
  *     (nla string, length 2)
  * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute)
  * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute)
+ * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag)
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -126,6 +127,7 @@ enum {
        HWSIM_ATTR_REG_HINT_ALPHA2,
        HWSIM_ATTR_REG_CUSTOM_REG,
        HWSIM_ATTR_REG_STRICT_REG,
+       HWSIM_ATTR_SUPPORT_P2P_DEVICE,
        __HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
index 8bfc07cd330e744f8fb68065b551181aa5857688..0948ebe8942ee3419c653c48a8bfa5f17f38c8e7 100644 (file)
@@ -1583,8 +1583,9 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
  * the function notifies the CFG802.11 subsystem of the new BSS connection.
  */
 static int
-mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
-                      u8 *bssid, int mode, struct ieee80211_channel *channel,
+mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len,
+                      const u8 *ssid, const u8 *bssid, int mode,
+                      struct ieee80211_channel *channel,
                       struct cfg80211_connect_params *sme, bool privacy)
 {
        struct cfg80211_ssid req_ssid;
@@ -1881,7 +1882,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                                     params->privacy);
 done:
        if (!ret) {
-               cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
+               cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
+                                    params->chandef.chan, GFP_KERNEL);
                dev_dbg(priv->adapter->dev,
                        "info: joined/created adhoc network with bssid"
                        " %pM successfully\n", priv->cfg_bssid);
index d8ad554ce39f566cbf95221317fca751482d7e5c..29d27d9b5ebe50909d9137b6a280335a2b660930 100644 (file)
@@ -1078,7 +1078,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
                       const u8 *key, int key_len, u8 key_index,
                       const u8 *mac_addr, int disable);
 
-int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
+int mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len);
 
 int mwifiex_get_ver_ext(struct mwifiex_private *priv);
 
index c5cb2ed19ec2e240d6a65a7bb9ee4165ad181b68..0bec94351f3684911cd02469636ea738a7ace774 100644 (file)
@@ -1391,7 +1391,7 @@ static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
  * with requisite parameters and calls the IOCTL handler.
  */
 int
-mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
+mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
 {
        struct mwifiex_ds_misc_gen_ie gen_ie;
 
index 5028557aa18adb1a22c74c7a59123f1bb52b0d5a..2e89a865a67d1023d9ae64e0351c42d91c15c47e 100644 (file)
@@ -2835,7 +2835,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
                                        bssid, req_ie, req_ie_len,
                                        resp_ie, resp_ie_len, GFP_KERNEL);
        } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
-               cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
+               cfg80211_ibss_joined(usbdev->net, bssid,
+                                    get_current_channel(usbdev, NULL),
+                                    GFP_KERNEL);
 
        kfree(info);
 
index a98acefb8c06a3802290c9130de368b8effcab83..ee28a1a3d0100deeb0b3a50296109e814528a85e 100644 (file)
@@ -260,8 +260,7 @@ static void rtl_rate_free_sta(void *rtlpriv,
        kfree(rate_priv);
 }
 
-static struct rate_control_ops rtl_rate_ops = {
-       .module = NULL,
+static const struct rate_control_ops rtl_rate_ops = {
        .name = "rtl_rc",
        .alloc = rtl_rate_alloc,
        .free = rtl_rate_free,
index aece6c9cccf1b50febc16049f4fd962c5c834aa7..27ace3054d5686869a336ce020a91737ff71bc2e 100644 (file)
@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
                        /* During testing, hdr was NULL */
                        return false;
                }
-               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                    (ieee80211_has_protected(hdr->frame_control)))
                        rx_status->flag &= ~RX_FLAG_DECRYPTED;
                else
index 52abf0a862fa70f26ec26ff62d2017f0a11ce5c9..114858d46158916600cdb6ad38e54723c8bd5618 100644 (file)
@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
                        /* In testing, hdr was NULL here */
                        return false;
                }
-               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                    (ieee80211_has_protected(hdr->frame_control)))
                        rx_status->flag &= ~RX_FLAG_DECRYPTED;
                else
index 27efbcdac6a979875976a7a74d1c15e07c1afa49..163a681962c621e6c817b19b54e0fbdc74ba22fd 100644 (file)
@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
                        /* during testing, hdr was NULL here */
                        return false;
                }
-               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                        (ieee80211_has_protected(hdr->frame_control)))
                        rx_status->flag &= ~RX_FLAG_DECRYPTED;
                else
index 50b7be3f3a605673756e543e456324993c66980d..721162cacc3a2009fa4a4a9e8f003a4a492fbd94 100644 (file)
@@ -334,7 +334,7 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
                        /* during testing, hdr could be NULL here */
                        return false;
                }
-               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+               if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
                        (ieee80211_has_protected(hdr->frame_control)))
                        rx_status->flag &= ~RX_FLAG_DECRYPTED;
                else
index e526a8cecb70a90533843bc26c90eaa2a7e23e55..5f349355ee54d4fda308b55234f743c509a5e207 100644 (file)
@@ -596,6 +596,20 @@ static inline int ieee80211_is_qos_nullfunc(__le16 fc)
               cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC);
 }
 
+/**
+ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU
+ * @fc: frame control field in little-endian byteorder
+ */
+static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc)
+{
+       /* IEEE 802.11-2012, definition of "bufferable management frame";
+        * note that this ignores the IBSS special case. */
+       return ieee80211_is_mgmt(fc) &&
+              (ieee80211_is_action(fc) ||
+               ieee80211_is_disassoc(fc) ||
+               ieee80211_is_deauth(fc));
+}
+
 /**
  * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set
  * @seq_ctrl: frame sequence control bytes in little-endian byteorder
@@ -1636,51 +1650,22 @@ enum ieee80211_reasoncode {
 enum ieee80211_eid {
        WLAN_EID_SSID = 0,
        WLAN_EID_SUPP_RATES = 1,
-       WLAN_EID_FH_PARAMS = 2,
+       WLAN_EID_FH_PARAMS = 2, /* reserved now */
        WLAN_EID_DS_PARAMS = 3,
        WLAN_EID_CF_PARAMS = 4,
        WLAN_EID_TIM = 5,
        WLAN_EID_IBSS_PARAMS = 6,
-       WLAN_EID_CHALLENGE = 16,
-
        WLAN_EID_COUNTRY = 7,
        WLAN_EID_HP_PARAMS = 8,
        WLAN_EID_HP_TABLE = 9,
        WLAN_EID_REQUEST = 10,
-
        WLAN_EID_QBSS_LOAD = 11,
        WLAN_EID_EDCA_PARAM_SET = 12,
        WLAN_EID_TSPEC = 13,
        WLAN_EID_TCLAS = 14,
        WLAN_EID_SCHEDULE = 15,
-       WLAN_EID_TS_DELAY = 43,
-       WLAN_EID_TCLAS_PROCESSING = 44,
-       WLAN_EID_QOS_CAPA = 46,
-       /* 802.11z */
-       WLAN_EID_LINK_ID = 101,
-       /* 802.11s */
-       WLAN_EID_MESH_CONFIG = 113,
-       WLAN_EID_MESH_ID = 114,
-       WLAN_EID_LINK_METRIC_REPORT = 115,
-       WLAN_EID_CONGESTION_NOTIFICATION = 116,
-       WLAN_EID_PEER_MGMT = 117,
-       WLAN_EID_CHAN_SWITCH_PARAM = 118,
-       WLAN_EID_MESH_AWAKE_WINDOW = 119,
-       WLAN_EID_BEACON_TIMING = 120,
-       WLAN_EID_MCCAOP_SETUP_REQ = 121,
-       WLAN_EID_MCCAOP_SETUP_RESP = 122,
-       WLAN_EID_MCCAOP_ADVERT = 123,
-       WLAN_EID_MCCAOP_TEARDOWN = 124,
-       WLAN_EID_GANN = 125,
-       WLAN_EID_RANN = 126,
-       WLAN_EID_PREQ = 130,
-       WLAN_EID_PREP = 131,
-       WLAN_EID_PERR = 132,
-       WLAN_EID_PXU = 137,
-       WLAN_EID_PXUC = 138,
-       WLAN_EID_AUTH_MESH_PEER_EXCH = 139,
-       WLAN_EID_MIC = 140,
-
+       WLAN_EID_CHALLENGE = 16,
+       /* 17-31 reserved for challenge text extension */
        WLAN_EID_PWR_CONSTRAINT = 32,
        WLAN_EID_PWR_CAPABILITY = 33,
        WLAN_EID_TPC_REQUEST = 34,
@@ -1691,66 +1676,114 @@ enum ieee80211_eid {
        WLAN_EID_MEASURE_REPORT = 39,
        WLAN_EID_QUIET = 40,
        WLAN_EID_IBSS_DFS = 41,
-
        WLAN_EID_ERP_INFO = 42,
-       WLAN_EID_EXT_SUPP_RATES = 50,
-
+       WLAN_EID_TS_DELAY = 43,
+       WLAN_EID_TCLAS_PROCESSING = 44,
        WLAN_EID_HT_CAPABILITY = 45,
-       WLAN_EID_HT_OPERATION = 61,
-       WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62,
-
+       WLAN_EID_QOS_CAPA = 46,
+       /* 47 reserved for Broadcom */
        WLAN_EID_RSN = 48,
-       WLAN_EID_MMIE = 76,
-       WLAN_EID_VENDOR_SPECIFIC = 221,
-       WLAN_EID_QOS_PARAMETER = 222,
-
+       WLAN_EID_802_15_COEX = 49,
+       WLAN_EID_EXT_SUPP_RATES = 50,
        WLAN_EID_AP_CHAN_REPORT = 51,
        WLAN_EID_NEIGHBOR_REPORT = 52,
        WLAN_EID_RCPI = 53,
+       WLAN_EID_MOBILITY_DOMAIN = 54,
+       WLAN_EID_FAST_BSS_TRANSITION = 55,
+       WLAN_EID_TIMEOUT_INTERVAL = 56,
+       WLAN_EID_RIC_DATA = 57,
+       WLAN_EID_DSE_REGISTERED_LOCATION = 58,
+       WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59,
+       WLAN_EID_EXT_CHANSWITCH_ANN = 60,
+       WLAN_EID_HT_OPERATION = 61,
+       WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62,
        WLAN_EID_BSS_AVG_ACCESS_DELAY = 63,
        WLAN_EID_ANTENNA_INFO = 64,
        WLAN_EID_RSNI = 65,
        WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66,
        WLAN_EID_BSS_AVAILABLE_CAPACITY = 67,
        WLAN_EID_BSS_AC_ACCESS_DELAY = 68,
+       WLAN_EID_TIME_ADVERTISEMENT = 69,
        WLAN_EID_RRM_ENABLED_CAPABILITIES = 70,
        WLAN_EID_MULTIPLE_BSSID = 71,
        WLAN_EID_BSS_COEX_2040 = 72,
        WLAN_EID_OVERLAP_BSS_SCAN_PARAM = 74,
-       WLAN_EID_EXT_CAPABILITY = 127,
-
-       WLAN_EID_MOBILITY_DOMAIN = 54,
-       WLAN_EID_FAST_BSS_TRANSITION = 55,
-       WLAN_EID_TIMEOUT_INTERVAL = 56,
-       WLAN_EID_RIC_DATA = 57,
        WLAN_EID_RIC_DESCRIPTOR = 75,
-
-       WLAN_EID_DSE_REGISTERED_LOCATION = 58,
-       WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59,
-       WLAN_EID_EXT_CHANSWITCH_ANN = 60,
-
-       WLAN_EID_VHT_CAPABILITY = 191,
-       WLAN_EID_VHT_OPERATION = 192,
-       WLAN_EID_OPMODE_NOTIF = 199,
-       WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194,
-       WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196,
-       WLAN_EID_EXTENDED_BSS_LOAD = 193,
-       WLAN_EID_VHT_TX_POWER_ENVELOPE = 195,
-       WLAN_EID_AID = 197,
-       WLAN_EID_QUIET_CHANNEL = 198,
-
-       /* 802.11ad */
+       WLAN_EID_MMIE = 76,
+       WLAN_EID_ASSOC_COMEBACK_TIME = 77,
+       WLAN_EID_EVENT_REQUEST = 78,
+       WLAN_EID_EVENT_REPORT = 79,
+       WLAN_EID_DIAGNOSTIC_REQUEST = 80,
+       WLAN_EID_DIAGNOSTIC_REPORT = 81,
+       WLAN_EID_LOCATION_PARAMS = 82,
        WLAN_EID_NON_TX_BSSID_CAP =  83,
+       WLAN_EID_SSID_LIST = 84,
+       WLAN_EID_MULTI_BSSID_IDX = 85,
+       WLAN_EID_FMS_DESCRIPTOR = 86,
+       WLAN_EID_FMS_REQUEST = 87,
+       WLAN_EID_FMS_RESPONSE = 88,
+       WLAN_EID_QOS_TRAFFIC_CAPA = 89,
+       WLAN_EID_BSS_MAX_IDLE_PERIOD = 90,
+       WLAN_EID_TSF_REQUEST = 91,
+       WLAN_EID_TSF_RESPOSNE = 92,
+       WLAN_EID_WNM_SLEEP_MODE = 93,
+       WLAN_EID_TIM_BCAST_REQ = 94,
+       WLAN_EID_TIM_BCAST_RESP = 95,
+       WLAN_EID_COLL_IF_REPORT = 96,
+       WLAN_EID_CHANNEL_USAGE = 97,
+       WLAN_EID_TIME_ZONE = 98,
+       WLAN_EID_DMS_REQUEST = 99,
+       WLAN_EID_DMS_RESPONSE = 100,
+       WLAN_EID_LINK_ID = 101,
+       WLAN_EID_WAKEUP_SCHEDUL = 102,
+       /* 103 reserved */
+       WLAN_EID_CHAN_SWITCH_TIMING = 104,
+       WLAN_EID_PTI_CONTROL = 105,
+       WLAN_EID_PU_BUFFER_STATUS = 106,
+       WLAN_EID_INTERWORKING = 107,
+       WLAN_EID_ADVERTISEMENT_PROTOCOL = 108,
+       WLAN_EID_EXPEDITED_BW_REQ = 109,
+       WLAN_EID_QOS_MAP_SET = 110,
+       WLAN_EID_ROAMING_CONSORTIUM = 111,
+       WLAN_EID_EMERGENCY_ALERT = 112,
+       WLAN_EID_MESH_CONFIG = 113,
+       WLAN_EID_MESH_ID = 114,
+       WLAN_EID_LINK_METRIC_REPORT = 115,
+       WLAN_EID_CONGESTION_NOTIFICATION = 116,
+       WLAN_EID_PEER_MGMT = 117,
+       WLAN_EID_CHAN_SWITCH_PARAM = 118,
+       WLAN_EID_MESH_AWAKE_WINDOW = 119,
+       WLAN_EID_BEACON_TIMING = 120,
+       WLAN_EID_MCCAOP_SETUP_REQ = 121,
+       WLAN_EID_MCCAOP_SETUP_RESP = 122,
+       WLAN_EID_MCCAOP_ADVERT = 123,
+       WLAN_EID_MCCAOP_TEARDOWN = 124,
+       WLAN_EID_GANN = 125,
+       WLAN_EID_RANN = 126,
+       WLAN_EID_EXT_CAPABILITY = 127,
+       /* 128, 129 reserved for Agere */
+       WLAN_EID_PREQ = 130,
+       WLAN_EID_PREP = 131,
+       WLAN_EID_PERR = 132,
+       /* 133-136 reserved for Cisco */
+       WLAN_EID_PXU = 137,
+       WLAN_EID_PXUC = 138,
+       WLAN_EID_AUTH_MESH_PEER_EXCH = 139,
+       WLAN_EID_MIC = 140,
+       WLAN_EID_DESTINATION_URI = 141,
+       WLAN_EID_UAPSD_COEX = 142,
        WLAN_EID_WAKEUP_SCHEDULE = 143,
        WLAN_EID_EXT_SCHEDULE = 144,
        WLAN_EID_STA_AVAILABILITY = 145,
        WLAN_EID_DMG_TSPEC = 146,
        WLAN_EID_DMG_AT = 147,
        WLAN_EID_DMG_CAP = 148,
+       /* 149-150 reserved for Cisco */
        WLAN_EID_DMG_OPERATION = 151,
        WLAN_EID_DMG_BSS_PARAM_CHANGE = 152,
        WLAN_EID_DMG_BEAM_REFINEMENT = 153,
        WLAN_EID_CHANNEL_MEASURE_FEEDBACK = 154,
+       /* 155-156 reserved for Cisco */
        WLAN_EID_AWAKE_WINDOW = 157,
        WLAN_EID_MULTI_BAND = 158,
        WLAN_EID_ADDBA_EXT = 159,
@@ -1767,11 +1800,34 @@ enum ieee80211_eid {
        WLAN_EID_MULTIPLE_MAC_ADDR = 170,
        WLAN_EID_U_PID = 171,
        WLAN_EID_DMG_LINK_ADAPT_ACK = 172,
+       /* 173 reserved for Symbol */
+       WLAN_EID_MCCAOP_ADV_OVERVIEW = 174,
        WLAN_EID_QUIET_PERIOD_REQ = 175,
+       /* 176 reserved for Symbol */
        WLAN_EID_QUIET_PERIOD_RESP = 177,
+       /* 178-179 reserved for Symbol */
+       /* 180 reserved for ISO/IEC 20011 */
        WLAN_EID_EPAC_POLICY = 182,
        WLAN_EID_CLISTER_TIME_OFF = 183,
+       WLAN_EID_INTER_AC_PRIO = 184,
+       WLAN_EID_SCS_DESCRIPTOR = 185,
+       WLAN_EID_QLOAD_REPORT = 186,
+       WLAN_EID_HCCA_TXOP_UPDATE_COUNT = 187,
+       WLAN_EID_HL_STREAM_ID = 188,
+       WLAN_EID_GCR_GROUP_ADDR = 189,
        WLAN_EID_ANTENNA_SECTOR_ID_PATTERN = 190,
+       WLAN_EID_VHT_CAPABILITY = 191,
+       WLAN_EID_VHT_OPERATION = 192,
+       WLAN_EID_EXTENDED_BSS_LOAD = 193,
+       WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194,
+       WLAN_EID_VHT_TX_POWER_ENVELOPE = 195,
+       WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196,
+       WLAN_EID_AID = 197,
+       WLAN_EID_QUIET_CHANNEL = 198,
+       WLAN_EID_OPMODE_NOTIF = 199,
+
+       WLAN_EID_VENDOR_SPECIFIC = 221,
+       WLAN_EID_QOS_PARAMETER = 222,
 };
 
 /* Action category code */
@@ -2192,10 +2248,10 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
 }
 
 /**
- * ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
+ * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame
  * @hdr: the frame (buffer must include at least the first octet of payload)
  */
-static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
+static inline bool _ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
 {
        if (ieee80211_is_disassoc(hdr->frame_control) ||
            ieee80211_is_deauth(hdr->frame_control))
@@ -2223,6 +2279,17 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
        return false;
 }
 
+/**
+ * ieee80211_is_robust_mgmt_frame - check if skb contains a robust mgmt frame
+ * @skb: the skb containing the frame, length will be checked
+ */
+static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
+{
+       if (skb->len < 25)
+               return false;
+       return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
+}
+
 /**
  * ieee80211_is_public_action - check if frame is a public action frame
  * @hdr: the frame
index b1f84b05c67e99371eef66c6c3adad1a45380f50..9f90554e88c48a1342c0d1116e1c47ba0b875d81 100644 (file)
@@ -1394,10 +1394,12 @@ struct cfg80211_scan_request {
 /**
  * struct cfg80211_match_set - sets of attributes to match
  *
- * @ssid: SSID to be matched
+ * @ssid: SSID to be matched; may be zero-length for no match (RSSI only)
+ * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
  */
 struct cfg80211_match_set {
        struct cfg80211_ssid ssid;
+       s32 rssi_thold;
 };
 
 /**
@@ -1420,7 +1422,8 @@ struct cfg80211_match_set {
  * @dev: the interface
  * @scan_start: start time of the scheduled scan
  * @channels: channels to scan
- * @rssi_thold: don't report scan results below this threshold (in s32 dBm)
+ * @min_rssi_thold: for drivers only supporting a single threshold, this
+ *     contains the minimum over all matchsets
  */
 struct cfg80211_sched_scan_request {
        struct cfg80211_ssid *ssids;
@@ -1433,7 +1436,7 @@ struct cfg80211_sched_scan_request {
        u32 flags;
        struct cfg80211_match_set *match_sets;
        int n_match_sets;
-       s32 rssi_thold;
+       s32 min_rssi_thold;
 
        /* internal */
        struct wiphy *wiphy;
@@ -1701,8 +1704,14 @@ struct cfg80211_ibss_params {
  *
  * @channel: The channel to use or %NULL if not specified (auto-select based
  *     on scan results)
+ * @channel_hint: The channel of the recommended BSS for initial connection or
+ *     %NULL if not specified
  * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan
  *     results)
+ * @bssid_hint: The recommended AP BSSID for initial connection to the BSS or
+ *     %NULL if not specified. Unlike the @bssid parameter, the driver is
+ *     allowed to ignore this @bssid_hint if it has knowledge of a better BSS
+ *     to use.
  * @ssid: SSID
  * @ssid_len: Length of ssid in octets
  * @auth_type: Authentication type (algorithm)
@@ -1725,11 +1734,13 @@ struct cfg80211_ibss_params {
  */
 struct cfg80211_connect_params {
        struct ieee80211_channel *channel;
-       u8 *bssid;
-       u8 *ssid;
+       struct ieee80211_channel *channel_hint;
+       const u8 *bssid;
+       const u8 *bssid_hint;
+       const u8 *ssid;
        size_t ssid_len;
        enum nl80211_auth_type auth_type;
-       u8 *ie;
+       const u8 *ie;
        size_t ie_len;
        bool privacy;
        enum nl80211_mfp mfp;
@@ -1768,6 +1779,7 @@ struct cfg80211_bitrate_mask {
                u32 legacy;
                u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
                u16 vht_mcs[NL80211_VHT_NSS_MAX];
+               enum nl80211_txrate_gi gi;
        } control[IEEE80211_NUM_BANDS];
 };
 /**
@@ -2875,6 +2887,11 @@ struct wiphy_vendor_command {
  * @n_vendor_commands: number of vendor commands
  * @vendor_events: array of vendor events supported by the hardware
  * @n_vendor_events: number of vendor events
+ *
+ * @max_ap_assoc_sta: maximum number of associated stations supported in AP mode
+ *     (including P2P GO) or 0 to indicate no such limit is advertised. The
+ *     driver is allowed to advertise a theoretical limit that it can reach in
+ *     some cases, but may not always reach.
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -2990,6 +3007,8 @@ struct wiphy {
        const struct nl80211_vendor_cmd_info *vendor_events;
        int n_vendor_commands, n_vendor_events;
 
+       u16 max_ap_assoc_sta;
+
        char priv[0] __aligned(NETDEV_ALIGN);
 };
 
@@ -3127,8 +3146,8 @@ struct cfg80211_cached_keys;
  * @identifier: (private) Identifier used in nl80211 to identify this
  *     wireless device if it has no netdev
  * @current_bss: (private) Used by the internal configuration code
- * @channel: (private) Used by the internal configuration code to track
- *     the user-set AP, monitor and WDS channel
+ * @chandef: (private) Used by the internal configuration code to track
+ *     the user-set channel definition.
  * @preset_chandef: (private) Used by the internal configuration code to
  *     track the channel to be used for AP later
  * @bssid: (private) Used by the internal configuration code
@@ -3192,9 +3211,7 @@ struct wireless_dev {
 
        struct cfg80211_internal_bss *current_bss; /* associated / joined */
        struct cfg80211_chan_def preset_chandef;
-
-       /* for AP and mesh channel tracking */
-       struct ieee80211_channel *channel;
+       struct cfg80211_chan_def chandef;
 
        bool ibss_fixed;
        bool ibss_dfs_possible;
@@ -3876,6 +3893,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  *
  * @dev: network device
  * @bssid: the BSSID of the IBSS joined
+ * @channel: the channel of the IBSS joined
  * @gfp: allocation flags
  *
  * This function notifies cfg80211 that the device joined an IBSS or
@@ -3885,7 +3903,8 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  * with the locally generated beacon -- this guarantees that there is
  * always a scan result for this IBSS. cfg80211 will handle the rest.
  */
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                         struct ieee80211_channel *channel, gfp_t gfp);
 
 /**
  * cfg80211_notify_new_candidate - notify cfg80211 of a new mesh peer candidate
index 8b5b714332971c547faa032574f56010f7ae3e15..b0fd9476c538eb78a62a6f72a555c1ddb9194426 100644 (file)
@@ -316,6 +316,10 @@ enum ieee80211_radiotap_type {
 #define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM                0x10
 #define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED                 0x20
 
+#define IEEE80211_RADIOTAP_CODING_LDPC_USER0                   0x01
+#define IEEE80211_RADIOTAP_CODING_LDPC_USER1                   0x02
+#define IEEE80211_RADIOTAP_CODING_LDPC_USER2                   0x04
+#define IEEE80211_RADIOTAP_CODING_LDPC_USER3                   0x08
 
 /* helpers */
 static inline int ieee80211_get_radiotap_len(unsigned char *data)
index f4ab2fb4d50c445b980e1f6c507ae5a893c1ddfc..4f0f29dce0aae64c98ffd9cf2cf6e26859e9c4d3 100644 (file)
@@ -808,9 +808,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
  * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
  * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
- * @RX_FLAG_80MHZ: 80 MHz was used
- * @RX_FLAG_80P80MHZ: 80+80 MHz was used
- * @RX_FLAG_160MHZ: 160 MHz was used
  * @RX_FLAG_SHORT_GI: Short guard interval was used
  * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
  *     Valid only for data frames (mainly A-MPDU)
@@ -830,6 +827,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  *     on this subframe
  * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
  *     is stored in the @ampdu_delimiter_crc field)
+ * @RX_FLAG_LDPC: LDPC was used
  * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
  * @RX_FLAG_10MHZ: 10 MHz (half channel) was used
  * @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used
@@ -866,9 +864,7 @@ enum mac80211_rx_flags {
        RX_FLAG_AMPDU_DELIM_CRC_KNOWN   = BIT(20),
        RX_FLAG_MACTIME_END             = BIT(21),
        RX_FLAG_VHT                     = BIT(22),
-       RX_FLAG_80MHZ                   = BIT(23),
-       RX_FLAG_80P80MHZ                = BIT(24),
-       RX_FLAG_160MHZ                  = BIT(25),
+       RX_FLAG_LDPC                    = BIT(23),
        RX_FLAG_STBC_MASK               = BIT(26) | BIT(27),
        RX_FLAG_10MHZ                   = BIT(28),
        RX_FLAG_5MHZ                    = BIT(29),
@@ -877,6 +873,21 @@ enum mac80211_rx_flags {
 
 #define RX_FLAG_STBC_SHIFT             26
 
+/**
+ * enum mac80211_rx_vht_flags - receive VHT flags
+ *
+ * These flags are used with the @vht_flag member of
+ *     &struct ieee80211_rx_status.
+ * @RX_VHT_FLAG_80MHZ: 80 MHz was used
+ * @RX_VHT_FLAG_80P80MHZ: 80+80 MHz was used
+ * @RX_VHT_FLAG_160MHZ: 160 MHz was used
+ */
+enum mac80211_rx_vht_flags {
+       RX_VHT_FLAG_80MHZ               = BIT(0),
+       RX_VHT_FLAG_80P80MHZ            = BIT(1),
+       RX_VHT_FLAG_160MHZ              = BIT(2),
+};
+
 /**
  * struct ieee80211_rx_status - receive status
  *
@@ -902,26 +913,19 @@ enum mac80211_rx_flags {
  *     HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
  * @vht_nss: number of streams (VHT only)
  * @flag: %RX_FLAG_*
+ * @vht_flag: %RX_VHT_FLAG_*
  * @rx_flags: internal RX flags for mac80211
  * @ampdu_reference: A-MPDU reference number, must be a different value for
  *     each A-MPDU but the same for each subframe within one A-MPDU
  * @ampdu_delimiter_crc: A-MPDU delimiter CRC
- * @vendor_radiotap_bitmap: radiotap vendor namespace presence bitmap
- * @vendor_radiotap_len: radiotap vendor namespace length
- * @vendor_radiotap_align: radiotap vendor namespace alignment. Note
- *     that the actual data must be at the start of the SKB data
- *     already.
- * @vendor_radiotap_oui: radiotap vendor namespace OUI
- * @vendor_radiotap_subns: radiotap vendor sub namespace
  */
 struct ieee80211_rx_status {
        u64 mactime;
        u32 device_timestamp;
        u32 ampdu_reference;
        u32 flag;
-       u32 vendor_radiotap_bitmap;
-       u16 vendor_radiotap_len;
        u16 freq;
+       u8 vht_flag;
        u8 rate_idx;
        u8 vht_nss;
        u8 rx_flags;
@@ -931,9 +935,6 @@ struct ieee80211_rx_status {
        u8 chains;
        s8 chain_signal[IEEE80211_MAX_CHAINS];
        u8 ampdu_delimiter_crc;
-       u8 vendor_radiotap_align;
-       u8 vendor_radiotap_oui[3];
-       u8 vendor_radiotap_subns;
 };
 
 /**
@@ -2750,11 +2751,13 @@ enum ieee80211_roc_type {
  * @channel_switch_beacon: Starts a channel switch to a new channel.
  *     Beacons are modified to include CSA or ECSA IEs before calling this
  *     function. The corresponding count fields in these IEs must be
- *     decremented, and when they reach zero the driver must call
+ *     decremented, and when they reach 1 the driver must call
  *     ieee80211_csa_finish(). Drivers which use ieee80211_beacon_get()
  *     get the csa counter decremented by mac80211, but must check if it is
- *     zero using ieee80211_csa_is_complete() after the beacon has been
+ *     1 using ieee80211_csa_is_complete() after the beacon has been
  *     transmitted and then call ieee80211_csa_finish().
+ *     If the CSA count starts as zero or 1, this function will not be called,
+ *     since there won't be any time to beacon before the switch anyway.
  *
  * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
  *     information in bss_conf is set up and the beacon can be retrieved. A
@@ -3452,13 +3455,13 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * After a channel switch announcement was scheduled and the counter in this
- * announcement hit zero, this function must be called by the driver to
+ * announcement hits 1, this function must be called by the driver to
  * notify mac80211 that the channel can be changed.
  */
 void ieee80211_csa_finish(struct ieee80211_vif *vif);
 
 /**
- * ieee80211_csa_is_complete - find out if counters reached zero
+ * ieee80211_csa_is_complete - find out if counters reached 1
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
  * This function returns whether the channel switch counters reached zero.
@@ -4451,7 +4454,6 @@ struct ieee80211_tx_rate_control {
 };
 
 struct rate_control_ops {
-       struct module *module;
        const char *name;
        void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir);
        void (*free)(void *priv);
@@ -4553,8 +4555,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw,
                           struct ieee80211_sta *pubsta,
                           struct ieee80211_sta_rates *rates);
 
-int ieee80211_rate_control_register(struct rate_control_ops *ops);
-void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
+int ieee80211_rate_control_register(const struct rate_control_ops *ops);
+void ieee80211_rate_control_unregister(const struct rate_control_ops *ops);
 
 static inline bool
 conf_is_ht20(struct ieee80211_conf *conf)
index 91054fd660e083156f02b826f0a5b812d7faac26..a12e6cae5132569815271c352508c48001c1b51e 100644 (file)
  *     %NL80211_ATTR_SSID attribute, and can optionally specify the association
  *     IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
  *     %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
- *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
- *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ *     %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ *     %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ *     %NL80211_ATTR_WIPHY_FREQ_HINT.
+ *     If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
+ *     restrictions on BSS selection, i.e., they effectively prevent roaming
+ *     within the ESS. %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT
+ *     can be included to provide a recommendation of the initial BSS while
+ *     allowing the driver to roam to other BSSes within the ESS and also to
+ *     ignore this recommendation if the indicated BSS is not ideal. Only one
+ *     set of BSSID,frequency parameters is used (i.e., either the enforcing
+ *     %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
+ *     %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
  *     Background scan period can optionally be
  *     specified in %NL80211_ATTR_BG_SCAN_PERIOD,
  *     if not specified default background scan configuration
@@ -1555,6 +1565,16 @@ enum nl80211_commands {
  *     data is in the format defined for the payload of the QoS Map Set element
  *     in IEEE Std 802.11-2012, 8.4.2.97.
  *
+ * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS
+ * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS
+ *
+ * @NL80211_ATTR_MAX_AP_ASSOC_STA: Device attribute that indicates how many
+ *     associated stations are supported in AP mode (including P2P GO); u32.
+ *     Since drivers may not have a fixed limit on the maximum number (e.g.,
+ *     other concurrent operations may affect this), drivers are allowed to
+ *     advertise values that cannot always be met. In such cases, an attempt
+ *     to add a new station entry with @NL80211_CMD_NEW_STATION may fail.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1883,6 +1903,11 @@ enum nl80211_attrs {
 
        NL80211_ATTR_QOS_MAP,
 
+       NL80211_ATTR_MAC_HINT,
+       NL80211_ATTR_WIPHY_FREQ_HINT,
+
+       NL80211_ATTR_MAX_AP_ASSOC_STA,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2412,7 +2437,10 @@ enum nl80211_reg_type {
  *     in KHz. This is not a center a frequency but an actual regulatory
  *     band edge.
  * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
- *     frequency range, in KHz.
+ *     frequency range, in KHz. If not present or 0, maximum available
+ *     bandwidth should be calculated base on contiguous rules and wider
+ *     channels will be allowed to cross multiple contiguous/overlapping
+ *     frequency ranges.
  * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
  *     for a given frequency range. The value is in mBi (100 * dBi).
  *     If you don't have one then don't send this.
@@ -2442,9 +2470,15 @@ enum nl80211_reg_rule_attr {
  * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
  * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
- * only report BSS with matching SSID.
+ *     only report BSS with matching SSID.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a
- *     BSS in scan results. Filtering is turned off if not specified.
+ *     BSS in scan results. Filtering is turned off if not specified. Note that
+ *     if this attribute is in a match set of its own, then it is treated as
+ *     the default value for all matchsets with an SSID, rather than being a
+ *     matchset of its own without an RSSI filter. This is due to problems with
+ *     how this API was implemented in the past. Also, due to the same problem,
+ *     the only way to create a matchset with only an RSSI filter (with this
+ *     attribute) is if there's only a single matchset with the RSSI attribute.
  * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
  *     attribute number currently defined
  * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3131,6 +3165,7 @@ enum nl80211_key_attributes {
  *     in an array of MCS numbers.
  * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection,
  *     see &struct nl80211_txrate_vht
+ * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi
  * @__NL80211_TXRATE_AFTER_LAST: internal
  * @NL80211_TXRATE_MAX: highest TX rate attribute
  */
@@ -3139,6 +3174,7 @@ enum nl80211_tx_rate_attributes {
        NL80211_TXRATE_LEGACY,
        NL80211_TXRATE_HT,
        NL80211_TXRATE_VHT,
+       NL80211_TXRATE_GI,
 
        /* keep last */
        __NL80211_TXRATE_AFTER_LAST,
@@ -3156,6 +3192,12 @@ struct nl80211_txrate_vht {
        __u16 mcs[NL80211_VHT_NSS_MAX];
 };
 
+enum nl80211_txrate_gi {
+       NL80211_TXRATE_DEFAULT_GI,
+       NL80211_TXRATE_FORCE_SGI,
+       NL80211_TXRATE_FORCE_LGI,
+};
+
 /**
  * enum nl80211_band - Frequency band
  * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
index 13b7683de5a455fe222c4148dc807471fe3b74bd..ce9633a3cfb0c54abe7aa87746f2b843cf33e65c 100644 (file)
@@ -107,7 +107,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.addba_req.start_seq_num =
                                        cpu_to_le16(start_seq_num << 4);
 
-       ieee80211_tx_skb_tid(sdata, skb, tid);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
index f9ae9b85d4c1bf297f3008e0f0693d6305c69824..6973ccdd230b88942ba71ceae911fb4d58424279 100644 (file)
@@ -451,11 +451,11 @@ void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
                rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
        if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
                rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
-       if (sta->last_rx_rate_flag & RX_FLAG_80MHZ)
+       if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80MHZ)
                rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
-       if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ)
+       if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_80P80MHZ)
                rinfo->flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
-       if (sta->last_rx_rate_flag & RX_FLAG_160MHZ)
+       if (sta->last_rx_rate_vht_flag & RX_VHT_FLAG_160MHZ)
                rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
 }
 
@@ -970,9 +970,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        /* TODO: make hostapd tell us what it wants */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
-       sdata->radar_required = params->radar_required;
 
        mutex_lock(&local->mtx);
+       sdata->radar_required = params->radar_required;
        err = ieee80211_vif_use_channel(sdata, &params->chandef,
                                        IEEE80211_CHANCTX_SHARED);
        mutex_unlock(&local->mtx);
@@ -1053,6 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
        int err;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       sdata_assert_lock(sdata);
 
        /* don't allow changing the beacon while CSA is in place - offset
         * of channel switch counter may change
@@ -1080,6 +1081,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        struct probe_resp *old_probe_resp;
        struct cfg80211_chan_def chandef;
 
+       sdata_assert_lock(sdata);
+
        old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (!old_beacon)
                return -ENOENT;
@@ -1341,6 +1344,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                    params->vht_capa, sta);
 
+       if (params->opmode_notif_used) {
+               enum ieee80211_band band =
+                       ieee80211_get_sdata_band(sdata);
+
+               /* returned value is only needed for rc update, but the
+                * rc isn't initialized here yet, so ignore it
+                */
+               __ieee80211_vht_handle_opmode(sdata, sta,
+                                             params->opmode_notif,
+                                             band, false);
+       }
+
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
                u32 changed = 0;
@@ -2628,6 +2643,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        if (!roc)
                return -ENOMEM;
 
+       /*
+        * If the duration is zero, then the driver
+        * wouldn't actually do anything. Set it to
+        * 10 for now.
+        *
+        * TODO: cancel the off-channel operation
+        *       when we get the SKB's TX status and
+        *       the wait time was zero before.
+        */
+       if (!duration)
+               duration = 10;
+
        roc->chan = channel;
        roc->duration = duration;
        roc->req_duration = duration;
@@ -2651,18 +2678,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
        /* otherwise actually kick it off here (for error handling) */
 
-       /*
-        * If the duration is zero, then the driver
-        * wouldn't actually do anything. Set it to
-        * 10 for now.
-        *
-        * TODO: cancel the off-channel operation
-        *       when we get the SKB's TX status and
-        *       the wait time was zero before.
-        */
-       if (!duration)
-               duration = 10;
-
        ret = drv_remain_on_channel(local, sdata, channel, duration, type);
        if (ret) {
                kfree(roc);
@@ -2988,69 +3003,88 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
        return new_beacon;
 }
 
-void ieee80211_csa_finalize_work(struct work_struct *work)
+void ieee80211_csa_finish(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       ieee80211_queue_work(&sdata->local->hw,
+                            &sdata->csa_finalize_work);
+}
+EXPORT_SYMBOL(ieee80211_csa_finish);
+
+static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data,
-                            csa_finalize_work);
        struct ieee80211_local *local = sdata->local;
        int err, changed = 0;
 
-       sdata_lock(sdata);
-       /* AP might have been stopped while waiting for the lock. */
-       if (!sdata->vif.csa_active)
-               goto unlock;
-
-       if (!ieee80211_sdata_running(sdata))
-               goto unlock;
+       sdata_assert_lock(sdata);
 
-       sdata->radar_required = sdata->csa_radar_required;
        mutex_lock(&local->mtx);
+       sdata->radar_required = sdata->csa_radar_required;
        err = ieee80211_vif_change_channel(sdata, &changed);
        mutex_unlock(&local->mtx);
        if (WARN_ON(err < 0))
-               goto unlock;
+               return;
 
        if (!local->use_chanctx) {
                local->_oper_chandef = sdata->csa_chandef;
                ieee80211_hw_config(local, 0);
        }
 
-       ieee80211_bss_info_change_notify(sdata, changed);
-
        sdata->vif.csa_active = false;
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
                err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
-               if (err < 0)
-                       goto unlock;
-
-               changed |= err;
                kfree(sdata->u.ap.next_beacon);
                sdata->u.ap.next_beacon = NULL;
 
-               ieee80211_bss_info_change_notify(sdata, err);
+               if (err < 0)
+                       return;
+               changed |= err;
                break;
        case NL80211_IFTYPE_ADHOC:
-               ieee80211_ibss_finish_csa(sdata);
+               err = ieee80211_ibss_finish_csa(sdata);
+               if (err < 0)
+                       return;
+               changed |= err;
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
                err = ieee80211_mesh_finish_csa(sdata);
                if (err < 0)
-                       goto unlock;
+                       return;
+               changed |= err;
                break;
 #endif
        default:
                WARN_ON(1);
-               goto unlock;
+               return;
        }
 
+       ieee80211_bss_info_change_notify(sdata, changed);
+
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
 
        cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+}
+
+void ieee80211_csa_finalize_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data,
+                            csa_finalize_work);
+
+       sdata_lock(sdata);
+       /* AP might have been stopped while waiting for the lock. */
+       if (!sdata->vif.csa_active)
+               goto unlock;
+
+       if (!ieee80211_sdata_running(sdata))
+               goto unlock;
+
+       ieee80211_csa_finalize(sdata);
 
 unlock:
        sdata_unlock(sdata);
@@ -3064,9 +3098,9 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_chanctx *chanctx;
        struct ieee80211_if_mesh __maybe_unused *ifmsh;
-       int err, num_chanctx;
+       int err, num_chanctx, changed = 0;
 
-       lockdep_assert_held(&sdata->wdev.mtx);
+       sdata_assert_lock(sdata);
 
        if (!list_empty(&local->roc_list) || local->scanning)
                return -EBUSY;
@@ -3105,19 +3139,40 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
-               sdata->csa_counter_offset_beacon =
-                       params->counter_offset_beacon;
-               sdata->csa_counter_offset_presp = params->counter_offset_presp;
                sdata->u.ap.next_beacon =
                        cfg80211_beacon_dup(&params->beacon_after);
                if (!sdata->u.ap.next_beacon)
                        return -ENOMEM;
 
+               /*
+                * With a count of 0, we don't have to wait for any
+                * TBTT before switching, so complete the CSA
+                * immediately.  In theory, with a count == 1 we
+                * should delay the switch until just before the next
+                * TBTT, but that would complicate things so we switch
+                * immediately too.  If we would delay the switch
+                * until the next TBTT, we would have to set the probe
+                * response here.
+                *
+                * TODO: A channel switch with count <= 1 without
+                * sending a CSA action frame is kind of useless,
+                * because the clients won't know we're changing
+                * channels.  The action frame must be implemented
+                * either here or in the userspace.
+                */
+               if (params->count <= 1)
+                       break;
+
+               sdata->csa_counter_offset_beacon =
+                       params->counter_offset_beacon;
+               sdata->csa_counter_offset_presp = params->counter_offset_presp;
                err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
                if (err < 0) {
                        kfree(sdata->u.ap.next_beacon);
                        return err;
                }
+               changed |= err;
+
                break;
        case NL80211_IFTYPE_ADHOC:
                if (!sdata->vif.bss_conf.ibss_joined)
@@ -3145,17 +3200,21 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                    params->chandef.chan->band)
                        return -EINVAL;
 
-               err = ieee80211_ibss_csa_beacon(sdata, params);
-               if (err < 0)
-                       return err;
+               /* see comments in the NL80211_IFTYPE_AP block */
+               if (params->count > 1) {
+                       err = ieee80211_ibss_csa_beacon(sdata, params);
+                       if (err < 0)
+                               return err;
+                       changed |= err;
+               }
+
+               ieee80211_send_action_csa(sdata, params);
+
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
                ifmsh = &sdata->u.mesh;
 
-               if (!ifmsh->mesh_id)
-                       return -EINVAL;
-
                if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
                        return -EINVAL;
 
@@ -3164,17 +3223,27 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                    params->chandef.chan->band)
                        return -EINVAL;
 
-               ifmsh->chsw_init = true;
-               if (!ifmsh->pre_value)
-                       ifmsh->pre_value = 1;
-               else
-                       ifmsh->pre_value++;
+               if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) {
+                       ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT;
+                       if (!ifmsh->pre_value)
+                               ifmsh->pre_value = 1;
+                       else
+                               ifmsh->pre_value++;
+               }
 
-               err = ieee80211_mesh_csa_beacon(sdata, params, true);
-               if (err < 0) {
-                       ifmsh->chsw_init = false;
-                       return err;
+               /* see comments in the NL80211_IFTYPE_AP block */
+               if (params->count > 1) {
+                       err = ieee80211_mesh_csa_beacon(sdata, params);
+                       if (err < 0) {
+                               ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
+                               return err;
+                       }
+                       changed |= err;
                }
+
+               if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
+                       ieee80211_send_action_csa(sdata, params);
+
                break;
 #endif
        default:
@@ -3191,8 +3260,13 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        sdata->csa_chandef = params->chandef;
        sdata->vif.csa_active = true;
 
-       ieee80211_bss_info_change_notify(sdata, err);
-       drv_channel_switch_beacon(sdata, &params->chandef);
+       if (changed) {
+               ieee80211_bss_info_change_notify(sdata, changed);
+               drv_channel_switch_beacon(sdata, &params->chandef);
+       } else {
+               /* if the beacon didn't change, we can finalize immediately */
+               ieee80211_csa_finalize(sdata);
+       }
 
        return 0;
 }
@@ -3863,7 +3937,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy,
        return 0;
 }
 
-struct cfg80211_ops mac80211_config_ops = {
+const struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
        .change_virtual_intf = ieee80211_change_iface,
index 7d7879f5b00b9d9fb7aa42ca8695d04e330dadb0..2d51f62dc76cd4978f1249c4a8ad1f95535a3e21 100644 (file)
@@ -4,6 +4,6 @@
 #ifndef __CFG_H
 #define __CFG_H
 
-extern struct cfg80211_ops mac80211_config_ops;
+extern const struct cfg80211_ops mac80211_config_ops;
 
 #endif /* __CFG_H */
index f43613a97dd664e2daf1856b001d7bdee5708d4f..42c659229a090a7c86f6ad42a33df11afd40b6c8 100644 (file)
@@ -196,6 +196,8 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
 
+       lockdep_assert_held(&local->mtx);
+
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (sdata->radar_required) {
index 80194b557a0cff8f3d2aba52f06cfc348212abf8..2ecb4deddb5df0ca74eb9630de15bbc9c789f274 100644 (file)
@@ -195,7 +195,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf,
                                    size_t count, loff_t *ppos)
 {
-       char _buf[12], *buf = _buf;
+       char _buf[12] = {}, *buf = _buf;
        struct sta_info *sta = file->private_data;
        bool start, tx;
        unsigned long tid;
index fab7b91923e0a8b93313797b53a469234ce83506..dc3c28002e3e2d99ee20f6d3809fe594d3796430 100644 (file)
@@ -375,7 +375,7 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.delba.params = cpu_to_le16(params);
        mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
 
-       ieee80211_tx_skb_tid(sdata, skb, tid);
+       ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
index 771080ec7212a43b5e3bb151a7e17ab392fe5557..9c84b75f3de8a58dc4f4e3cbf8a0c0c72be63ab3 100644 (file)
@@ -220,7 +220,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_supported_band *sband;
        struct ieee80211_mgmt *mgmt;
        struct cfg80211_bss *bss;
        u32 bss_change;
@@ -294,7 +293,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        }
 
        mutex_lock(&local->mtx);
-       ieee80211_vif_release_channel(sdata);
        if (ieee80211_vif_use_channel(sdata, &chandef,
                                      ifibss->fixed_channel ?
                                        IEEE80211_CHANCTX_SHARED :
@@ -303,12 +301,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                mutex_unlock(&local->mtx);
                return;
        }
+       sdata->radar_required = radar_required;
        mutex_unlock(&local->mtx);
 
        memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
-       sband = local->hw.wiphy->bands[chan->band];
-
        presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
                                           capability, tsf, &chandef,
                                           &have_higher_than_11mbit, NULL);
@@ -318,7 +315,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        rcu_assign_pointer(ifibss->presp, presp);
        mgmt = (void *)presp->head;
 
-       sdata->radar_required = radar_required;
        sdata->vif.bss_conf.enable_beacon = true;
        sdata->vif.bss_conf.beacon_int = beacon_int;
        sdata->vif.bss_conf.basic_rates = basic_rates;
@@ -386,7 +382,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                              presp->head_len, 0, GFP_KERNEL);
        cfg80211_put_bss(local->hw.wiphy, bss);
        netif_carrier_on(sdata->dev);
-       cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
+       cfg80211_ibss_joined(sdata->dev, ifibss->bssid, chan, GFP_KERNEL);
 }
 
 static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -521,12 +517,6 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
        if (old_presp)
                kfree_rcu(old_presp, rcu_head);
 
-       /* it might not send the beacon for a while. send an action frame
-        * immediately to announce the channel switch.
-        */
-       if (csa_settings)
-               ieee80211_send_action_csa(sdata, csa_settings);
-
        return BSS_CHANGED_BEACON;
  out:
        return ret;
@@ -536,7 +526,7 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct cfg80211_bss *cbss;
-       int err;
+       int err, changed = 0;
        u16 capability;
 
        sdata_assert_lock(sdata);
@@ -568,10 +558,9 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
        if (err < 0)
                return err;
 
-       if (err)
-               ieee80211_bss_info_change_notify(sdata, err);
+       changed |= err;
 
-       return 0;
+       return changed;
 }
 
 void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
@@ -802,6 +791,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        int err;
        u32 sta_flags;
 
+       sdata_assert_lock(sdata);
+
        sta_flags = IEEE80211_STA_DISABLE_VHT;
        switch (ifibss->chandef.width) {
        case NL80211_CHAN_WIDTH_5:
@@ -1471,6 +1462,11 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN);
        ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa);
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+
+       /* avoid excessive retries for probe request to wildcard SSIDs */
+       if (pos[1] == 0)
+               IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_NO_ACK;
+
        ieee80211_tx_skb(sdata, skb);
 }
 
index 3701930c66493af53461a4f0c1849ad26450e092..0014b5396ce5a4212a978af3f6f9f7594a9de60f 100644 (file)
@@ -616,7 +616,11 @@ struct ieee80211_if_mesh {
        struct ps_data ps;
        /* Channel Switching Support */
        struct mesh_csa_settings __rcu *csa;
-       bool chsw_init;
+       enum {
+               IEEE80211_MESH_CSA_ROLE_NONE,
+               IEEE80211_MESH_CSA_ROLE_INIT,
+               IEEE80211_MESH_CSA_ROLE_REPEATER,
+       } csa_role;
        u8 chsw_ttl;
        u16 pre_value;
 
@@ -1408,8 +1412,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                   struct sk_buff *skb);
 int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
-                             struct cfg80211_csa_settings *csa_settings,
-                             bool csa_action);
+                             struct cfg80211_csa_settings *csa_settings);
 int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata);
 
 /* scan/BSS handling */
@@ -1553,6 +1556,9 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct sta_info *sta);
 enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
 void ieee80211_sta_set_rx_nss(struct sta_info *sta);
+u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
+                                  struct sta_info *sta, u8 opmode,
+                                  enum ieee80211_band band, bool nss_only);
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                 struct sta_info *sta, u8 opmode,
                                 enum ieee80211_band band, bool nss_only);
@@ -1605,7 +1611,7 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw)
 }
 
 /* utility functions/constants */
-extern void *mac80211_wiphy_privid; /* for wiphy privid */
+extern const void *const mac80211_wiphy_privid; /* for wiphy privid */
 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
                        enum nl80211_iftype type);
 int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
index 3dfd20a453aba250fff726d1733f0dac6c763b3c..8880bc8fce0dc9d20a118efd9667218ea62f4b1e 100644 (file)
@@ -822,7 +822,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        cancel_work_sync(&local->dynamic_ps_enable_work);
 
        cancel_work_sync(&sdata->recalc_smps);
+       sdata_lock(sdata);
        sdata->vif.csa_active = false;
+       sdata_unlock(sdata);
        cancel_work_sync(&sdata->csa_finalize_work);
 
        cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
index d767cfb9b45f092606cd37288113e82714b75fe4..1f7d8422d62d865e1d6b2f84021681e0718c898c 100644 (file)
@@ -893,10 +893,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        /* mac80211 supports control port protocol changing */
        local->hw.wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
 
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-       else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
+       } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
                local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+               if (hw->max_signal <= 0) {
+                       result = -EINVAL;
+                       goto fail_wiphy_register;
+               }
+       }
 
        WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
             && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
index 5b919cab1de0015cd833d04b840c9d7cdc69e96b..f70e9cd10552dac6729d703edd2e9ae12750a3a6 100644 (file)
@@ -688,7 +688,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                *pos++ = csa->settings.count;
                *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;
                *pos++ = 6;
-               if (ifmsh->chsw_init) {
+               if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) {
                        *pos++ = ifmsh->mshcfg.dot11MeshTTL;
                        *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
                } else {
@@ -859,18 +859,12 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
 {
        struct cfg80211_csa_settings params;
        struct ieee80211_csa_ie csa_ie;
-       struct ieee80211_chanctx_conf *chanctx_conf;
-       struct ieee80211_chanctx *chanctx;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
-       int err, num_chanctx;
+       int err;
        u32 sta_flags;
 
-       if (sdata->vif.csa_active)
-               return true;
-
-       if (!ifmsh->mesh_id)
-               return false;
+       sdata_assert_lock(sdata);
 
        sta_flags = IEEE80211_STA_DISABLE_VHT;
        switch (sdata->vif.bss_conf.chandef.width) {
@@ -896,10 +890,6 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
        params.chandef = csa_ie.chandef;
        params.count = csa_ie.count;
 
-       if (sdata->vif.bss_conf.chandef.chan->band !=
-           params.chandef.chan->band)
-               return false;
-
        if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
                                     IEEE80211_CHAN_DISABLED)) {
                sdata_info(sdata,
@@ -922,24 +912,12 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
                return false;
        }
 
-       rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
-       if (!chanctx_conf)
-               goto failed_chswitch;
-
-       /* don't handle for multi-VIF cases */
-       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
-       if (chanctx->refcount > 1)
-               goto failed_chswitch;
-
-       num_chanctx = 0;
-       list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
-               num_chanctx++;
-
-       if (num_chanctx > 1)
-               goto failed_chswitch;
-
-       rcu_read_unlock();
+       if (cfg80211_chandef_identical(&params.chandef,
+                                      &sdata->vif.bss_conf.chandef)) {
+               mcsa_dbg(sdata,
+                        "received csa with an identical chandef, ignoring\n");
+               return true;
+       }
 
        mcsa_dbg(sdata,
                 "received channel switch announcement to go to channel %d MHz\n",
@@ -953,30 +931,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
                ifmsh->pre_value = csa_ie.pre_value;
        }
 
-       if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) {
-               if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
-                       return false;
-       } else {
+       if (ifmsh->chsw_ttl >= ifmsh->mshcfg.dot11MeshTTL)
                return false;
-       }
 
-       sdata->csa_radar_required = params.radar_required;
+       ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_REPEATER;
 
-       if (params.block_tx)
-               ieee80211_stop_queues_by_reason(&sdata->local->hw,
-                               IEEE80211_MAX_QUEUE_MAP,
-                               IEEE80211_QUEUE_STOP_REASON_CSA);
-
-       sdata->csa_chandef = params.chandef;
-       sdata->vif.csa_active = true;
-
-       ieee80211_bss_info_change_notify(sdata, err);
-       drv_channel_switch_beacon(sdata, &params.chandef);
+       if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev,
+                                    &params) < 0)
+               return false;
 
        return true;
-failed_chswitch:
-       rcu_read_unlock();
-       return false;
 }
 
 static void
@@ -1086,7 +1050,8 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
                ifmsh->sync_ops->rx_bcn_presp(sdata,
                        stype, mgmt, &elems, rx_status);
 
-       if (!ifmsh->chsw_init)
+       if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
+           !sdata->vif.csa_active)
                ieee80211_mesh_process_chnswitch(sdata, &elems, true);
 }
 
@@ -1095,29 +1060,30 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct mesh_csa_settings *tmp_csa_settings;
        int ret = 0;
+       int changed = 0;
 
        /* Reset the TTL value and Initiator flag */
-       ifmsh->chsw_init = false;
+       ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
        ifmsh->chsw_ttl = 0;
 
        /* Remove the CSA and MCSP elements from the beacon */
        tmp_csa_settings = rcu_dereference(ifmsh->csa);
        rcu_assign_pointer(ifmsh->csa, NULL);
-       kfree_rcu(tmp_csa_settings, rcu_head);
+       if (tmp_csa_settings)
+               kfree_rcu(tmp_csa_settings, rcu_head);
        ret = ieee80211_mesh_rebuild_beacon(sdata);
        if (ret)
                return -EINVAL;
 
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+       changed |= BSS_CHANGED_BEACON;
 
        mcsa_dbg(sdata, "complete switching to center freq %d MHz",
                 sdata->vif.bss_conf.chandef.chan->center_freq);
-       return 0;
+       return changed;
 }
 
 int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
-                             struct cfg80211_csa_settings *csa_settings,
-                             bool csa_action)
+                             struct cfg80211_csa_settings *csa_settings)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct mesh_csa_settings *tmp_csa_settings;
@@ -1141,12 +1107,7 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
                return ret;
        }
 
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
-
-       if (csa_action)
-               ieee80211_send_action_csa(sdata, csa_settings);
-
-       return 0;
+       return BSS_CHANGED_BEACON;
 }
 
 static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
@@ -1210,7 +1171,8 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
 
        ifmsh->pre_value = pre_value;
 
-       if (!ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
+       if (!sdata->vif.csa_active &&
+           !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
                mcsa_dbg(sdata, "Failed to process CSA action frame");
                return;
        }
@@ -1257,7 +1219,7 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        sdata_lock(sdata);
 
        /* mesh already went down */
-       if (!sdata->wdev.mesh_id_len)
+       if (!sdata->u.mesh.mesh_id_len)
                goto out;
 
        rx_status = IEEE80211_SKB_RXCB(skb);
@@ -1310,7 +1272,7 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
        sdata_lock(sdata);
 
        /* mesh already went down */
-       if (!sdata->wdev.mesh_id_len)
+       if (!sdata->u.mesh.mesh_id_len)
                goto out;
 
        if (ifmsh->preq_queue_len &&
@@ -1365,7 +1327,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
        mesh_rmc_init(sdata);
        ifmsh->last_preq = jiffies;
        ifmsh->next_perr = jiffies;
-       ifmsh->chsw_init = false;
+       ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
        /* Allocate all mesh structures when creating the first mesh interface. */
        if (!mesh_allocated)
                ieee80211s_init();
index fc1d82465b3ce1b1cdcc9edb4f5157618b70e8ce..61604834b9146c0b1c6d7360570120d432c1c2c2 100644 (file)
@@ -508,6 +508,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
        u8 *pos;
        u32 cap;
        struct ieee80211_sta_vht_cap vht_cap;
+       u32 mask, ap_bf_sts, our_bf_sts;
 
        BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
 
@@ -535,6 +536,16 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
                        cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)))
                cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
 
+       mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+
+       ap_bf_sts = le32_to_cpu(ap_vht_cap->vht_cap_info) & mask;
+       our_bf_sts = cap & mask;
+
+       if (ap_bf_sts < our_bf_sts) {
+               cap &= ~mask;
+               cap |= ap_bf_sts;
+       }
+
        /* reserve and fill IE */
        pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
        ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
@@ -745,6 +756,34 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
                                    sband, chan, sdata->smps_mode);
 
+       /* if present, add any custom IEs that go before VHT */
+       if (assoc_data->ie_len) {
+               static const u8 before_vht[] = {
+                       WLAN_EID_SSID,
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_EXT_SUPP_RATES,
+                       WLAN_EID_PWR_CAPABILITY,
+                       WLAN_EID_SUPPORTED_CHANNELS,
+                       WLAN_EID_RSN,
+                       WLAN_EID_QOS_CAPA,
+                       WLAN_EID_RRM_ENABLED_CAPABILITIES,
+                       WLAN_EID_MOBILITY_DOMAIN,
+                       WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+                       WLAN_EID_HT_CAPABILITY,
+                       WLAN_EID_BSS_COEX_2040,
+                       WLAN_EID_EXT_CAPABILITY,
+                       WLAN_EID_QOS_TRAFFIC_CAPA,
+                       WLAN_EID_TIM_BCAST_REQ,
+                       WLAN_EID_INTERWORKING,
+               };
+               noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
+                                            before_vht, ARRAY_SIZE(before_vht),
+                                            offset);
+               pos = skb_put(skb, noffset - offset);
+               memcpy(pos, assoc_data->ie + offset, noffset - offset);
+               offset = noffset;
+       }
+
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                ieee80211_add_vht_ie(sdata, skb, sband,
                                     &assoc_data->ap_vht_cap);
@@ -1001,7 +1040,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
 
        ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
-       sdata->vif.csa_active = true;
 
        mutex_lock(&local->chanctx_mtx);
        if (local->use_chanctx) {
@@ -1039,6 +1077,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        mutex_unlock(&local->chanctx_mtx);
 
        sdata->csa_chandef = csa_ie.chandef;
+       sdata->vif.csa_active = true;
 
        if (csa_ie.mode)
                ieee80211_stop_queues_by_reason(&local->hw,
index 22b223f13c9fa22994eba6f68769a27b2cfe4eb3..8fdadfd94ba8576ae8bc0ee2e99e8c656c2f6a5b 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/rtnetlink.h>
-#include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include "rate.h"
 #include "ieee80211_i.h"
 #include "debugfs.h"
 
 struct rate_control_alg {
        struct list_head list;
-       struct rate_control_ops *ops;
+       const struct rate_control_ops *ops;
 };
 
 static LIST_HEAD(rate_ctrl_algs);
@@ -29,7 +29,7 @@ module_param(ieee80211_default_rc_algo, charp, 0644);
 MODULE_PARM_DESC(ieee80211_default_rc_algo,
                 "Default rate control algorithm for mac80211 to use");
 
-int ieee80211_rate_control_register(struct rate_control_ops *ops)
+int ieee80211_rate_control_register(const struct rate_control_ops *ops)
 {
        struct rate_control_alg *alg;
 
@@ -60,7 +60,7 @@ int ieee80211_rate_control_register(struct rate_control_ops *ops)
 }
 EXPORT_SYMBOL(ieee80211_rate_control_register);
 
-void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
+void ieee80211_rate_control_unregister(const struct rate_control_ops *ops)
 {
        struct rate_control_alg *alg;
 
@@ -76,32 +76,31 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
 }
 EXPORT_SYMBOL(ieee80211_rate_control_unregister);
 
-static struct rate_control_ops *
+static const struct rate_control_ops *
 ieee80211_try_rate_control_ops_get(const char *name)
 {
        struct rate_control_alg *alg;
-       struct rate_control_ops *ops = NULL;
+       const struct rate_control_ops *ops = NULL;
 
        if (!name)
                return NULL;
 
        mutex_lock(&rate_ctrl_mutex);
        list_for_each_entry(alg, &rate_ctrl_algs, list) {
-               if (!strcmp(alg->ops->name, name))
-                       if (try_module_get(alg->ops->module)) {
-                               ops = alg->ops;
-                               break;
-                       }
+               if (!strcmp(alg->ops->name, name)) {
+                       ops = alg->ops;
+                       break;
+               }
        }
        mutex_unlock(&rate_ctrl_mutex);
        return ops;
 }
 
 /* Get the rate control algorithm. */
-static struct rate_control_ops *
+static const struct rate_control_ops *
 ieee80211_rate_control_ops_get(const char *name)
 {
-       struct rate_control_ops *ops;
+       const struct rate_control_ops *ops;
        const char *alg_name;
 
        kparam_block_sysfs_write(ieee80211_default_rc_algo);
@@ -111,10 +110,6 @@ ieee80211_rate_control_ops_get(const char *name)
                alg_name = name;
 
        ops = ieee80211_try_rate_control_ops_get(alg_name);
-       if (!ops) {
-               request_module("rc80211_%s", alg_name);
-               ops = ieee80211_try_rate_control_ops_get(alg_name);
-       }
        if (!ops && name)
                /* try default if specific alg requested but not found */
                ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
@@ -127,11 +122,6 @@ ieee80211_rate_control_ops_get(const char *name)
        return ops;
 }
 
-static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
-{
-       module_put(ops->module);
-}
-
 #ifdef CONFIG_MAC80211_DEBUGFS
 static ssize_t rcname_read(struct file *file, char __user *userbuf,
                           size_t count, loff_t *ppos)
@@ -158,11 +148,11 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
 
        ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
        if (!ref)
-               goto fail_ref;
+               return NULL;
        ref->local = local;
        ref->ops = ieee80211_rate_control_ops_get(name);
        if (!ref->ops)
-               goto fail_ops;
+               goto free;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir);
@@ -172,14 +162,11 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
 
        ref->priv = ref->ops->alloc(&local->hw, debugfsdir);
        if (!ref->priv)
-               goto fail_priv;
+               goto free;
        return ref;
 
-fail_priv:
-       ieee80211_rate_control_ops_put(ref->ops);
-fail_ops:
+free:
        kfree(ref);
-fail_ref:
        return NULL;
 }
 
@@ -192,7 +179,6 @@ static void rate_control_free(struct rate_control_ref *ctrl_ref)
        ctrl_ref->local->debugfs.rcdir = NULL;
 #endif
 
-       ieee80211_rate_control_ops_put(ctrl_ref->ops);
        kfree(ctrl_ref);
 }
 
index b95e16c070813da22169679e8c5c1aa7e3ee0f1d..9aa2a1190a86353a25deca879018b2750bdefad9 100644 (file)
@@ -21,7 +21,7 @@
 
 struct rate_control_ref {
        struct ieee80211_local *local;
-       struct rate_control_ops *ops;
+       const struct rate_control_ops *ops;
        void *priv;
 };
 
index f3d88b0c054c219fde20b907195c3bdb5a481c97..26fd94fa0aedb86e43382781f791b1f36de44954 100644 (file)
@@ -657,7 +657,7 @@ minstrel_free(void *priv)
        kfree(priv);
 }
 
-struct rate_control_ops mac80211_minstrel = {
+const struct rate_control_ops mac80211_minstrel = {
        .name = "minstrel",
        .tx_status = minstrel_tx_status,
        .get_rate = minstrel_get_rate,
index f4301f4b2e418f1e325ccd78c4c2a6986303ca36..046d1bd598a86d114c5c4dd6a7c7edb75808af13 100644 (file)
@@ -123,7 +123,7 @@ struct minstrel_debugfs_info {
        char buf[];
 };
 
-extern struct rate_control_ops mac80211_minstrel;
+extern const struct rate_control_ops mac80211_minstrel;
 void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
 void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
 
index c1b5b73c5b91353597eb1dfcf7a0f70946c72562..bccaf854a309e9434fb9044d0e98082e3de287de 100644 (file)
@@ -124,7 +124,7 @@ const struct mcs_group minstrel_mcs_groups[] = {
 
 #define MINSTREL_CCK_GROUP     (ARRAY_SIZE(minstrel_mcs_groups) - 1)
 
-static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
+static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
 
 static void
 minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
@@ -1031,7 +1031,7 @@ minstrel_ht_free(void *priv)
        mac80211_minstrel.free(priv);
 }
 
-static struct rate_control_ops mac80211_minstrel_ht = {
+static const struct rate_control_ops mac80211_minstrel_ht = {
        .name = "minstrel_ht",
        .tx_status = minstrel_ht_tx_status,
        .get_rate = minstrel_ht_get_rate,
@@ -1048,8 +1048,7 @@ static struct rate_control_ops mac80211_minstrel_ht = {
 };
 
 
-static void
-init_sample_table(void)
+static void __init init_sample_table(void)
 {
        int col, i, new_idx;
        u8 rnd[MCS_GROUP_RATES];
index 958fad07b54cf64856e3600bd6299f4ca9abd72a..d0da2a70fe6899e7cf4f9733225d3846186f1780 100644 (file)
@@ -452,7 +452,7 @@ static void rate_control_pid_free_sta(void *priv, struct ieee80211_sta *sta,
        kfree(priv_sta);
 }
 
-static struct rate_control_ops mac80211_rcpid = {
+static const struct rate_control_ops mac80211_rcpid = {
        .name = "pid",
        .tx_status = rate_control_pid_tx_status,
        .get_rate = rate_control_pid_get_rate,
index c24ca0d0f4697ea7040c813dbf24d1c32f707329..593062109c50231d7d131e2165ddb96d7359a35d 100644 (file)
@@ -40,8 +40,6 @@
 static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
                                           struct sk_buff *skb)
 {
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
                if (likely(skb->len > FCS_LEN))
                        __pskb_trim(skb, skb->len - FCS_LEN);
@@ -53,9 +51,6 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
                }
        }
 
-       if (status->vendor_radiotap_len)
-               __pskb_pull(skb, status->vendor_radiotap_len);
-
        return skb;
 }
 
@@ -64,14 +59,13 @@ static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr;
 
-       hdr = (void *)(skb->data + status->vendor_radiotap_len);
+       hdr = (void *)(skb->data);
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
                            RX_FLAG_FAILED_PLCP_CRC |
                            RX_FLAG_AMPDU_IS_ZEROLEN))
                return 1;
-       if (unlikely(skb->len < 16 + present_fcs_len +
-                               status->vendor_radiotap_len))
+       if (unlikely(skb->len < 16 + present_fcs_len))
                return 1;
        if (ieee80211_is_ctl(hdr->frame_control) &&
            !ieee80211_is_pspoll(hdr->frame_control) &&
@@ -90,8 +84,6 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
        len = sizeof(struct ieee80211_radiotap_header) + 8;
 
        /* allocate extra bitmaps */
-       if (status->vendor_radiotap_len)
-               len += 4;
        if (status->chains)
                len += 4 * hweight8(status->chains);
 
@@ -127,18 +119,6 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local,
                len += 2 * hweight8(status->chains);
        }
 
-       if (status->vendor_radiotap_len) {
-               if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
-                       status->vendor_radiotap_align = 1;
-               /* align standard part of vendor namespace */
-               len = ALIGN(len, 2);
-               /* allocate standard part of vendor namespace */
-               len += 6;
-               /* align vendor-defined part */
-               len = ALIGN(len, status->vendor_radiotap_align);
-               /* vendor-defined part is already in skb */
-       }
-
        return len;
 }
 
@@ -172,7 +152,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        it_present = &rthdr->it_present;
 
        /* radiotap header, set always present flags */
-       rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
+       rthdr->it_len = cpu_to_le16(rtap_len);
        it_present_val = BIT(IEEE80211_RADIOTAP_FLAGS) |
                         BIT(IEEE80211_RADIOTAP_CHANNEL) |
                         BIT(IEEE80211_RADIOTAP_RX_FLAGS);
@@ -190,14 +170,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                                 BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
        }
 
-       if (status->vendor_radiotap_len) {
-               it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |
-                                 BIT(IEEE80211_RADIOTAP_EXT);
-               put_unaligned_le32(it_present_val, it_present);
-               it_present++;
-               it_present_val = status->vendor_radiotap_bitmap;
-       }
-
        put_unaligned_le32(it_present_val, it_present);
 
        pos = (void *)(it_present + 1);
@@ -307,6 +279,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                        *pos |= IEEE80211_RADIOTAP_MCS_BW_40;
                if (status->flag & RX_FLAG_HT_GF)
                        *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF;
+               if (status->flag & RX_FLAG_LDPC)
+                       *pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC;
                stbc = (status->flag & RX_FLAG_STBC_MASK) >> RX_FLAG_STBC_SHIFT;
                *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT;
                pos++;
@@ -349,20 +323,23 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 
                rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT);
                /* known field - how to handle 80+80? */
-               if (status->flag & RX_FLAG_80P80MHZ)
+               if (status->vht_flag & RX_VHT_FLAG_80P80MHZ)
                        known &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
                put_unaligned_le16(known, pos);
                pos += 2;
                /* flags */
                if (status->flag & RX_FLAG_SHORT_GI)
                        *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
+               /* in VHT, STBC is binary */
+               if (status->flag & RX_FLAG_STBC_MASK)
+                       *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
                pos++;
                /* bandwidth */
-               if (status->flag & RX_FLAG_80MHZ)
+               if (status->vht_flag & RX_VHT_FLAG_80MHZ)
                        *pos++ = 4;
-               else if (status->flag & RX_FLAG_80P80MHZ)
+               else if (status->vht_flag & RX_VHT_FLAG_80P80MHZ)
                        *pos++ = 0; /* marked not known above */
-               else if (status->flag & RX_FLAG_160MHZ)
+               else if (status->vht_flag & RX_VHT_FLAG_160MHZ)
                        *pos++ = 11;
                else if (status->flag & RX_FLAG_40MHZ)
                        *pos++ = 1;
@@ -372,6 +349,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                *pos = (status->rate_idx << 4) | status->vht_nss;
                pos += 4;
                /* coding field */
+               if (status->flag & RX_FLAG_LDPC)
+                       *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0;
                pos++;
                /* group ID */
                pos++;
@@ -383,21 +362,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                *pos++ = status->chain_signal[chain];
                *pos++ = chain;
        }
-
-       if (status->vendor_radiotap_len) {
-               /* ensure 2 byte alignment for the vendor field as required */
-               if ((pos - (u8 *)rthdr) & 1)
-                       *pos++ = 0;
-               *pos++ = status->vendor_radiotap_oui[0];
-               *pos++ = status->vendor_radiotap_oui[1];
-               *pos++ = status->vendor_radiotap_oui[2];
-               *pos++ = status->vendor_radiotap_subns;
-               put_unaligned_le16(status->vendor_radiotap_len, pos);
-               pos += 2;
-               /* align the actual payload as requested */
-               while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1))
-                       *pos++ = 0;
-       }
 }
 
 /*
@@ -428,8 +392,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
 
-       /* ensure hdr->frame_control and vendor radiotap data are in skb head */
-       if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) {
+       /* ensure hdr->frame_control is in skb head */
+       if (!pskb_may_pull(origskb, 2)) {
                dev_kfree_skb(origskb);
                return NULL;
        }
@@ -599,10 +563,10 @@ static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 
-       if (skb->len < 24 || is_multicast_ether_addr(hdr->addr1))
+       if (is_multicast_ether_addr(hdr->addr1))
                return 0;
 
-       return ieee80211_is_robust_mgmt_frame(hdr);
+       return ieee80211_is_robust_mgmt_frame(skb);
 }
 
 
@@ -610,10 +574,10 @@ static int ieee80211_is_multicast_robust_mgmt_frame(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 
-       if (skb->len < 24 || !is_multicast_ether_addr(hdr->addr1))
+       if (!is_multicast_ether_addr(hdr->addr1))
                return 0;
 
-       return ieee80211_is_robust_mgmt_frame(hdr);
+       return ieee80211_is_robust_mgmt_frame(skb);
 }
 
 
@@ -626,7 +590,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
                return -1;
 
-       if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
+       if (!ieee80211_is_robust_mgmt_frame(skb))
                return -1; /* not a robust management frame */
 
        mmie = (struct ieee80211_mmie *)
@@ -1261,6 +1225,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                        if (ieee80211_is_data(hdr->frame_control)) {
                                sta->last_rx_rate_idx = status->rate_idx;
                                sta->last_rx_rate_flag = status->flag;
+                               sta->last_rx_rate_vht_flag = status->vht_flag;
                                sta->last_rx_rate_vht_nss = status->vht_nss;
                        }
                }
@@ -1311,18 +1276,15 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
            !ieee80211_has_morefrags(hdr->frame_control) &&
            !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
            (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
-            rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) {
+            rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
+           /* PM bit is only checked in frames where it isn't reserved,
+            * in AP mode it's reserved in non-bufferable management frames
+            * (cf. IEEE 802.11-2012 8.2.4.1.7 Power Management field)
+            */
+           (!ieee80211_is_mgmt(hdr->frame_control) ||
+            ieee80211_is_bufferable_mmpdu(hdr->frame_control))) {
                if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
-                       /*
-                        * Ignore doze->wake transitions that are
-                        * indicated by non-data frames, the standard
-                        * is unclear here, but for example going to
-                        * PS mode and then scanning would cause a
-                        * doze->wake transition for the probe request,
-                        * and that is clearly undesirable.
-                        */
-                       if (ieee80211_is_data(hdr->frame_control) &&
-                           !ieee80211_has_pm(hdr->frame_control))
+                       if (!ieee80211_has_pm(hdr->frame_control))
                                sta_ps_end(sta);
                } else {
                        if (ieee80211_has_pm(hdr->frame_control))
@@ -1845,8 +1807,7 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
                 * having configured keys.
                 */
                if (unlikely(ieee80211_is_action(fc) && !rx->key &&
-                            ieee80211_is_robust_mgmt_frame(
-                                    (struct ieee80211_hdr *) rx->skb->data)))
+                            ieee80211_is_robust_mgmt_frame(rx->skb)))
                        return -EACCES;
        }
 
index d77ff70906303855458734a5bfac0526460056eb..d4d85de0d75df91d23b35a6e657b301ff2e589c6 100644 (file)
@@ -261,6 +261,7 @@ struct ieee80211_tx_latency_stat {
  *     "the" transmit rate
  * @last_rx_rate_idx: rx status rate index of the last data packet
  * @last_rx_rate_flag: rx status flag of the last data packet
+ * @last_rx_rate_vht_flag: rx status vht flag of the last data packet
  * @last_rx_rate_vht_nss: rx status nss of last data packet
  * @lock: used for locking all fields that require locking, see comments
  *     in the header file.
@@ -397,6 +398,7 @@ struct sta_info {
        struct ieee80211_tx_rate last_tx_rate;
        int last_rx_rate_idx;
        u32 last_rx_rate_flag;
+       u32 last_rx_rate_vht_flag;
        u8 last_rx_rate_vht_nss;
        u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 
index 1ee85c402439bfc886029f9ae6dfe6ec306e013f..e6e574a307c8f3fd552329379919aaf9d071245d 100644 (file)
@@ -479,7 +479,7 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
        u32 msrmnt;
        u16 tid;
        u8 *qc;
-       int i, bin_range_count, bin_count;
+       int i, bin_range_count;
        u32 *bin_ranges;
        __le16 fc;
        struct ieee80211_tx_latency_stat *tx_lat;
@@ -522,7 +522,6 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
        /* count how many Tx frames transmitted with the appropriate latency */
        bin_range_count = tx_latency->n_ranges;
        bin_ranges = tx_latency->ranges;
-       bin_count = tx_lat->bin_count;
 
        for (i = 0; i < bin_range_count; i++) {
                if (msrmnt <= bin_ranges[i]) {
index 27c990bf2320237aa3c3124e25d0b0bc9508fb40..5476a69b45c9244123dd21dbd60882b3f98b6e70 100644 (file)
@@ -452,8 +452,7 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
        if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
                return 0;
 
-       if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *)
-                                           skb->data))
+       if (!ieee80211_is_robust_mgmt_frame(skb))
                return 0;
 
        return 1;
@@ -523,11 +522,8 @@ ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
        if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
                return TX_CONTINUE;
 
-       /* only deauth, disassoc and action are bufferable MMPDUs */
        if (ieee80211_is_mgmt(hdr->frame_control) &&
-           !ieee80211_is_deauth(hdr->frame_control) &&
-           !ieee80211_is_disassoc(hdr->frame_control) &&
-           !ieee80211_is_action(hdr->frame_control)) {
+           !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
                if (tx->flags & IEEE80211_TX_UNICAST)
                        info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
                return TX_CONTINUE;
@@ -567,7 +563,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                tx->key = key;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
                 is_multicast_ether_addr(hdr->addr1) &&
-                ieee80211_is_robust_mgmt_frame(hdr) &&
+                ieee80211_is_robust_mgmt_frame(tx->skb) &&
                 (key = rcu_dereference(tx->sdata->default_mgmt_key)))
                tx->key = key;
        else if (is_multicast_ether_addr(hdr->addr1) &&
@@ -582,12 +578,12 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                tx->key = NULL;
        else if (tx->skb->protocol == tx->sdata->control_port_protocol)
                tx->key = NULL;
-       else if (ieee80211_is_robust_mgmt_frame(hdr) &&
+       else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
                 !(ieee80211_is_action(hdr->frame_control) &&
                   tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
                tx->key = NULL;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
-                !ieee80211_is_robust_mgmt_frame(hdr))
+                !ieee80211_is_robust_mgmt_frame(tx->skb))
                tx->key = NULL;
        else {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
@@ -2402,15 +2398,6 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-void ieee80211_csa_finish(struct ieee80211_vif *vif)
-{
-       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-
-       ieee80211_queue_work(&sdata->local->hw,
-                            &sdata->csa_finalize_work);
-}
-EXPORT_SYMBOL(ieee80211_csa_finish);
-
 static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
                                 struct beacon_data *beacon)
 {
@@ -2439,8 +2426,12 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON(counter_offset_beacon >= beacon_data_len))
                return;
 
-       /* warn if the driver did not check for/react to csa completeness */
-       if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
+       /* Warn if the driver did not check for/react to csa
+        * completeness.  A beacon with CSA counter set to 0 should
+        * never occur, because a counter of 1 means switch just
+        * before the next beacon.
+        */
+       if (WARN_ON(beacon_data[counter_offset_beacon] == 1))
                return;
 
        beacon_data[counter_offset_beacon]--;
@@ -2506,7 +2497,7 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
        if (WARN_ON(counter_beacon > beacon_data_len))
                goto out;
 
-       if (beacon_data[counter_beacon] == 0)
+       if (beacon_data[counter_beacon] == 1)
                ret = true;
  out:
        rcu_read_unlock();
index 676dc0967f377f1251a761bf2dff0c35c8e92346..d842af5c8a9520d206f0860ee23d0dba41e44a38 100644 (file)
@@ -34,7 +34,7 @@
 #include "wep.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
-void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
+const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid;
 
 struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
 {
@@ -1281,13 +1281,32 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
         * that calculates local->scan_ies_len.
         */
 
-       /* add any remaining custom IEs */
+       /* insert custom IEs that go before VHT */
        if (ie && ie_len) {
-               noffset = ie_len;
+               static const u8 before_vht[] = {
+                       WLAN_EID_SSID,
+                       WLAN_EID_SUPP_RATES,
+                       WLAN_EID_REQUEST,
+                       WLAN_EID_EXT_SUPP_RATES,
+                       WLAN_EID_DS_PARAMS,
+                       WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+                       WLAN_EID_HT_CAPABILITY,
+                       WLAN_EID_BSS_COEX_2040,
+                       WLAN_EID_EXT_CAPABILITY,
+                       WLAN_EID_SSID_LIST,
+                       WLAN_EID_CHANNEL_USAGE,
+                       WLAN_EID_INTERWORKING,
+                       /* mesh ID can't happen here */
+                       /* 60 GHz can't happen here right now */
+               };
+               noffset = ieee80211_ie_split(ie, ie_len,
+                                            before_vht, ARRAY_SIZE(before_vht),
+                                            offset);
                if (end - pos < noffset - offset)
                        goto out_err;
                memcpy(pos, ie + offset, noffset - offset);
                pos += noffset - offset;
+               offset = noffset;
        }
 
        if (sband->vht_cap.vht_supported) {
@@ -1297,6 +1316,15 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                                                 sband->vht_cap.cap);
        }
 
+       /* add any remaining custom IEs */
+       if (ie && ie_len) {
+               noffset = ie_len;
+               if (end - pos < noffset - offset)
+                       goto out_err;
+               memcpy(pos, ie + offset, noffset - offset);
+               pos += noffset - offset;
+       }
+
        return pos - buffer;
  out_err:
        WARN_ONCE(1, "not enough space for preq IEs\n");
@@ -1374,7 +1402,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
                            enum ieee80211_band band, u32 *basic_rates)
 {
        struct ieee80211_supported_band *sband;
-       struct ieee80211_rate *bitrates;
        size_t num_rates;
        u32 supp_rates, rate_flags;
        int i, j, shift;
@@ -1386,7 +1413,6 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
        if (WARN_ON(!sband))
                return 1;
 
-       bitrates = sband->bitrates;
        num_rates = sband->n_bitrates;
        supp_rates = 0;
        for (i = 0; i < elems->supp_rates_len +
@@ -2272,11 +2298,11 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
                ri.nss = status->vht_nss;
                if (status->flag & RX_FLAG_40MHZ)
                        ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
-               if (status->flag & RX_FLAG_80MHZ)
+               if (status->vht_flag & RX_VHT_FLAG_80MHZ)
                        ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
-               if (status->flag & RX_FLAG_80P80MHZ)
+               if (status->vht_flag & RX_VHT_FLAG_80P80MHZ)
                        ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
-               if (status->flag & RX_FLAG_160MHZ)
+               if (status->vht_flag & RX_VHT_FLAG_160MHZ)
                        ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
                if (status->flag & RX_FLAG_SHORT_GI)
                        ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
index d75f35c6e1a0884eb9452030cb27bcafb33deeab..e9e36a256165842ac112e35e612ba79c8f86d305 100644 (file)
@@ -349,9 +349,9 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta)
        sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss);
 }
 
-void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
-                                struct sta_info *sta, u8 opmode,
-                                enum ieee80211_band band, bool nss_only)
+u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
+                                 struct sta_info *sta, u8 opmode,
+                                 enum ieee80211_band band, bool nss_only)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
@@ -363,7 +363,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 
        /* ignore - no support for BF yet */
        if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
-               return;
+               return 0;
 
        nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
        nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
@@ -375,7 +375,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
        }
 
        if (nss_only)
-               goto change;
+               return changed;
 
        switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
@@ -398,7 +398,19 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                changed |= IEEE80211_RC_BW_CHANGED;
        }
 
- change:
-       if (changed)
+       return changed;
+}
+
+void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
+                                struct sta_info *sta, u8 opmode,
+                                enum ieee80211_band band, bool nss_only)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
+
+       u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode,
+                                                   band, nss_only);
+
+       if (changed > 0)
                rate_control_rate_update(local, sband, sta, changed);
 }
index 21448d629b152adebff514e5d5a8d37e11a676e6..b8600e3c29c828d918b3676397f73a4d0fe7892c 100644 (file)
@@ -301,8 +301,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
 }
 
 
-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
-                               int encrypted)
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
 {
        __le16 mask_fc;
        int a4_included, mgmt;
@@ -456,7 +455,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
                return 0;
 
        pos += IEEE80211_CCMP_HDR_LEN;
-       ccmp_special_blocks(skb, pn, b_0, aad, 0);
+       ccmp_special_blocks(skb, pn, b_0, aad);
        ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
                                  skb_put(skb, IEEE80211_CCMP_MIC_LEN));
 
@@ -495,7 +494,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
        if (!ieee80211_is_data(hdr->frame_control) &&
-           !ieee80211_is_robust_mgmt_frame(hdr))
+           !ieee80211_is_robust_mgmt_frame(skb))
                return RX_CONTINUE;
 
        data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN -
@@ -524,7 +523,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
                u8 aad[2 * AES_BLOCK_SIZE];
                u8 b_0[AES_BLOCK_SIZE];
                /* hardware didn't decrypt/verify MIC */
-               ccmp_special_blocks(skb, pn, b_0, aad, 1);
+               ccmp_special_blocks(skb, pn, b_0, aad);
 
                if (ieee80211_aes_ccm_decrypt(
                            key->u.ccmp.tfm, b_0, aad,
index ed7e0b4e7f90730b7530bbcf20106deaeb3d48bd..b3b16c070a7fae95c6bc5a5bdd087ce436476c5a 100644 (file)
@@ -789,7 +789,8 @@ void rfkill_resume_polling(struct rfkill *rfkill)
        if (!rfkill->ops->poll)
                return;
 
-       schedule_work(&rfkill->poll_work.work);
+       queue_delayed_work(system_power_efficient_wq,
+                          &rfkill->poll_work, 0);
 }
 EXPORT_SYMBOL(rfkill_resume_polling);
 
@@ -894,7 +895,8 @@ static void rfkill_poll(struct work_struct *work)
         */
        rfkill->ops->poll(rfkill, rfkill->data);
 
-       schedule_delayed_work(&rfkill->poll_work,
+       queue_delayed_work(system_power_efficient_wq,
+               &rfkill->poll_work,
                round_jiffies_relative(POLL_INTERVAL));
 }
 
@@ -958,7 +960,8 @@ int __must_check rfkill_register(struct rfkill *rfkill)
        INIT_WORK(&rfkill->sync_work, rfkill_sync_work);
 
        if (rfkill->ops->poll)
-               schedule_delayed_work(&rfkill->poll_work,
+               queue_delayed_work(system_power_efficient_wq,
+                       &rfkill->poll_work,
                        round_jiffies_relative(POLL_INTERVAL));
 
        if (!rfkill->persistent || rfkill_epo_lock_active) {
index 11ee4ed04f73ea2ae0dd1ae6293837785d8fd5f8..68602be07cc10ae1ff0b4356e6e2a95492e34717 100644 (file)
@@ -27,9 +27,10 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
        err = rdev_stop_ap(rdev, dev);
        if (!err) {
                wdev->beacon_interval = 0;
-               wdev->channel = NULL;
+               memset(&wdev->chandef, 0, sizeof(wdev->chandef));
                wdev->ssid_len = 0;
                rdev_set_qos_map(rdev, dev, NULL);
+               nl80211_send_ap_stopped(wdev);
        }
 
        return err;
index 78559b5bbd1fe1d98c533f18dd1cc4fce4087baa..f8ab7df1ab0dc8f0a3bfadf13a6dfd08caa5dd54 100644 (file)
@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
 void
 cfg80211_get_chan_state(struct wireless_dev *wdev,
                        struct ieee80211_channel **chan,
-                       enum cfg80211_chan_mode *chanmode)
+                       enum cfg80211_chan_mode *chanmode,
+                       u8 *radar_detect)
 {
        *chan = NULL;
        *chanmode = CHAN_MODE_UNDEFINED;
@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                                     !wdev->ibss_dfs_possible)
                                  ? CHAN_MODE_SHARED
                                  : CHAN_MODE_EXCLUSIVE;
+
+                       /* consider worst-case - IBSS can try to return to the
+                        * original user-specified channel as creator */
+                       if (wdev->ibss_dfs_possible)
+                               *radar_detect |= BIT(wdev->chandef.width);
                        return;
                }
                break;
@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
                if (wdev->cac_started) {
-                       *chan = wdev->channel;
+                       *chan = wdev->chandef.chan;
                        *chanmode = CHAN_MODE_SHARED;
+                       *radar_detect |= BIT(wdev->chandef.width);
                } else if (wdev->beacon_interval) {
-                       *chan = wdev->channel;
+                       *chan = wdev->chandef.chan;
                        *chanmode = CHAN_MODE_SHARED;
+
+                       if (cfg80211_chandef_dfs_required(wdev->wiphy,
+                                                         &wdev->chandef))
+                               *radar_detect |= BIT(wdev->chandef.width);
                }
                return;
        case NL80211_IFTYPE_MESH_POINT:
                if (wdev->mesh_id_len) {
-                       *chan = wdev->channel;
+                       *chan = wdev->chandef.chan;
                        *chanmode = CHAN_MODE_SHARED;
+
+                       if (cfg80211_chandef_dfs_required(wdev->wiphy,
+                                                         &wdev->chandef))
+                               *radar_detect |= BIT(wdev->chandef.width);
                }
                return;
        case NL80211_IFTYPE_MONITOR:
index d89dee2259b5994b9237100425aae0a3f21b20af..b5ff39a6f6ed9949a828b2391ad5bdf284ab54b9 100644 (file)
@@ -737,7 +737,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
-static struct device_type wiphy_type = {
+static const struct device_type wiphy_type = {
        .name   = "wlan",
 };
 
index 37ec16d7bb1ab6bf6e4948259aad19eb6e5a58cf..9895ab16c0510d2fcbf631d8120ec535beed7db8 100644 (file)
@@ -210,6 +210,7 @@ struct cfg80211_event {
                } dc;
                struct {
                        u8 bssid[ETH_ALEN];
+                       struct ieee80211_channel *channel;
                } ij;
        };
 };
@@ -257,7 +258,8 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                          struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, bool nowext);
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                           struct ieee80211_channel *channel);
 int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
                            struct wireless_dev *wdev);
 
@@ -441,7 +443,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
 void
 cfg80211_get_chan_state(struct wireless_dev *wdev,
                        struct ieee80211_channel **chan,
-                       enum cfg80211_chan_mode *chanmode);
+                       enum cfg80211_chan_mode *chanmode,
+                       u8 *radar_detect);
 
 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
                                 struct cfg80211_chan_def *chandef);
index f911c5f9f903d8ccdd791aaf26d950b19ad6dd9f..1470b90e438f4bf6306be3591fdf6d376676ec5f 100644 (file)
@@ -14,7 +14,8 @@
 #include "rdev-ops.h"
 
 
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
+void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                           struct ieee80211_channel *channel)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_bss *bss;
@@ -28,8 +29,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
        if (!wdev->ssid_len)
                return;
 
-       bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-                              wdev->ssid, wdev->ssid_len,
+       bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
                               WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
 
        if (WARN_ON(!bss))
@@ -54,21 +54,26 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
 #endif
 }
 
-void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
+void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
+                         struct ieee80211_channel *channel, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct cfg80211_event *ev;
        unsigned long flags;
 
-       trace_cfg80211_ibss_joined(dev, bssid);
+       trace_cfg80211_ibss_joined(dev, bssid, channel);
+
+       if (WARN_ON(!channel))
+               return;
 
        ev = kzalloc(sizeof(*ev), gfp);
        if (!ev)
                return;
 
        ev->type = EVENT_IBSS_JOINED;
-       memcpy(ev->cr.bssid, bssid, ETH_ALEN);
+       memcpy(ev->ij.bssid, bssid, ETH_ALEN);
+       ev->ij.channel = channel;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
        list_add_tail(&ev->list, &wdev->event_list);
@@ -117,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 
        wdev->ibss_fixed = params->channel_fixed;
        wdev->ibss_dfs_possible = params->userspace_handles_dfs;
+       wdev->chandef = params->chandef;
 #ifdef CONFIG_CFG80211_WEXT
        wdev->wext.ibss.chandef = params->chandef;
 #endif
@@ -200,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 
        wdev->current_bss = NULL;
        wdev->ssid_len = 0;
+       memset(&wdev->chandef, 0, sizeof(wdev->chandef));
 #ifdef CONFIG_CFG80211_WEXT
        if (!nowext)
                wdev->wext.ibss.ssid_len = 0;
index 885862447b63c3434c0784924de2b984fcfedc25..d42a3fcb2f67ae0fb7a563f07ee74f96fa17fee7 100644 (file)
@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        if (!err) {
                memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
                wdev->mesh_id_len = setup->mesh_id_len;
-               wdev->channel = setup->chandef.chan;
+               wdev->chandef = setup->chandef;
        }
 
        return err;
@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
                err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
                                                     chandef->chan);
                if (!err)
-                       wdev->channel = chandef->chan;
+                       wdev->chandef = *chandef;
 
                return err;
        }
@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
        err = rdev_leave_mesh(rdev, dev);
        if (!err) {
                wdev->mesh_id_len = 0;
-               wdev->channel = NULL;
+               memset(&wdev->chandef, 0, sizeof(wdev->chandef));
                rdev_set_qos_map(rdev, dev, NULL);
        }
 
index 52cca05044a898b977927f2c9e540b00d6811634..d47c9d127b1eef3bef4e8d00f65dcf1392d70c2d 100644 (file)
@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev,
        if (WARN_ON(!wdev->cac_started))
                return;
 
-       if (WARN_ON(!wdev->channel))
+       if (WARN_ON(!wdev->chandef.chan))
                return;
 
        switch (event) {
index 7a742594916e177461a5374693e78c07bcbce09b..ebea1a197afb368faadfc90d1f97f2ffa6e1bcff 100644 (file)
@@ -382,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
        [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
                                   .len = IEEE80211_QOS_MAP_LEN_MAX },
+       [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
+       [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
 };
 
 /* policy for the key attributes */
@@ -855,6 +857,19 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
        return 0;
 }
 
+static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
+                                                       struct nlattr *tb)
+{
+       struct ieee80211_channel *chan;
+
+       if (tb == NULL)
+               return NULL;
+       chan = ieee80211_get_channel(wiphy, nla_get_u32(tb));
+       if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
+               return NULL;
+       return chan;
+}
+
 static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
 {
        struct nlattr *nl_modes = nla_nest_start(msg, attr);
@@ -1586,6 +1601,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                    (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
                     nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
                        goto nla_put_failure;
+
+               if (dev->wiphy.max_ap_assoc_sta &&
+                   nla_put_u32(msg, NL80211_ATTR_MAX_AP_ASSOC_STA,
+                               dev->wiphy.max_ap_assoc_sta))
+                       goto nla_put_failure;
+
                state->split_start++;
                break;
        case 11:
@@ -2034,10 +2055,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                    rem_txq_params) {
-                       nla_parse(tb, NL80211_TXQ_ATTR_MAX,
-                                 nla_data(nl_txq_params),
-                                 nla_len(nl_txq_params),
-                                 txq_params_policy);
+                       result = nla_parse(tb, NL80211_TXQ_ATTR_MAX,
+                                          nla_data(nl_txq_params),
+                                          nla_len(nl_txq_params),
+                                          txq_params_policy);
+                       if (result)
+                               return result;
                        result = parse_txq_params(tb, &txq_params);
                        if (result)
                                return result;
@@ -3258,7 +3281,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        if (!err) {
                wdev->preset_chandef = params.chandef;
                wdev->beacon_interval = params.beacon_interval;
-               wdev->channel = params.chandef.chan;
+               wdev->chandef = params.chandef;
                wdev->ssid_len = params.ssid_len;
                memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
        }
@@ -3901,8 +3924,8 @@ static struct net_device *get_vlan(struct genl_info *info,
        return ERR_PTR(ret);
 }
 
-static struct nla_policy
-nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
+static const struct nla_policy
+nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
        [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
        [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
 };
@@ -4603,8 +4626,6 @@ static int parse_reg_rule(struct nlattr *tb[],
                return -EINVAL;
        if (!tb[NL80211_ATTR_FREQ_RANGE_END])
                return -EINVAL;
-       if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
-               return -EINVAL;
        if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
                return -EINVAL;
 
@@ -4614,8 +4635,9 @@ static int parse_reg_rule(struct nlattr *tb[],
                nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
        freq_range->end_freq_khz =
                nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
-       freq_range->max_bandwidth_khz =
-               nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
+       if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+               freq_range->max_bandwidth_khz =
+                       nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
 
        power_rule->max_eirp =
                nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
@@ -5085,6 +5107,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
                const struct ieee80211_reg_rule *reg_rule;
                const struct ieee80211_freq_range *freq_range;
                const struct ieee80211_power_rule *power_rule;
+               unsigned int max_bandwidth_khz;
 
                reg_rule = &regdom->reg_rules[i];
                freq_range = &reg_rule->freq_range;
@@ -5094,6 +5117,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
                if (!nl_reg_rule)
                        goto nla_put_failure_rcu;
 
+               max_bandwidth_khz = freq_range->max_bandwidth_khz;
+               if (!max_bandwidth_khz)
+                       max_bandwidth_khz = reg_get_max_bandwidth(regdom,
+                                                                 reg_rule);
+
                if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
                                reg_rule->flags) ||
                    nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_START,
@@ -5101,7 +5129,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
                    nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_END,
                                freq_range->end_freq_khz) ||
                    nla_put_u32(msg, NL80211_ATTR_FREQ_RANGE_MAX_BW,
-                               freq_range->max_bandwidth_khz) ||
+                               max_bandwidth_khz) ||
                    nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
                                power_rule->max_antenna_gain) ||
                    nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
@@ -5177,9 +5205,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 
        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
                            rem_reg_rules) {
-               nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
-                         nla_data(nl_reg_rule), nla_len(nl_reg_rule),
-                         reg_rule_policy);
+               r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
+                             nla_data(nl_reg_rule), nla_len(nl_reg_rule),
+                             reg_rule_policy);
+               if (r)
+                       goto bad_reg;
                r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
                if (r)
                        goto bad_reg;
@@ -5442,6 +5472,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        enum ieee80211_band band;
        size_t ie_len;
        struct nlattr *tb[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1];
+       s32 default_match_rssi = NL80211_SCAN_RSSI_THOLD_OFF;
 
        if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
            !rdev->ops->sched_scan_start)
@@ -5476,11 +5507,40 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        if (n_ssids > wiphy->max_sched_scan_ssids)
                return -EINVAL;
 
-       if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH])
+       /*
+        * First, count the number of 'real' matchsets. Due to an issue with
+        * the old implementation, matchsets containing only the RSSI attribute
+        * (NL80211_SCHED_SCAN_MATCH_ATTR_RSSI) are considered as the 'default'
+        * RSSI for all matchsets, rather than their own matchset for reporting
+        * all APs with a strong RSSI. This is needed to be compatible with
+        * older userspace that treated a matchset with only the RSSI as the
+        * global RSSI for all other matchsets - if there are other matchsets.
+        */
+       if (info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH]) {
                nla_for_each_nested(attr,
                                    info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH],
-                                   tmp)
-                       n_match_sets++;
+                                   tmp) {
+                       struct nlattr *rssi;
+
+                       err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
+                                       nla_data(attr), nla_len(attr),
+                                       nl80211_match_policy);
+                       if (err)
+                               return err;
+                       /* add other standalone attributes here */
+                       if (tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]) {
+                               n_match_sets++;
+                               continue;
+                       }
+                       rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
+                       if (rssi)
+                               default_match_rssi = nla_get_s32(rssi);
+               }
+       }
+
+       /* However, if there's no other matchset, add the RSSI one */
+       if (!n_match_sets && default_match_rssi != NL80211_SCAN_RSSI_THOLD_OFF)
+               n_match_sets = 1;
 
        if (n_match_sets > wiphy->max_match_sets)
                return -EINVAL;
@@ -5601,11 +5661,22 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                                    tmp) {
                        struct nlattr *ssid, *rssi;
 
-                       nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
-                                 nla_data(attr), nla_len(attr),
-                                 nl80211_match_policy);
+                       err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
+                                       nla_data(attr), nla_len(attr),
+                                       nl80211_match_policy);
+                       if (err)
+                               goto out_free;
                        ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
                        if (ssid) {
+                               if (WARN_ON(i >= n_match_sets)) {
+                                       /* this indicates a programming error,
+                                        * the loop above should have verified
+                                        * things properly
+                                        */
+                                       err = -EINVAL;
+                                       goto out_free;
+                               }
+
                                if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
                                        err = -EINVAL;
                                        goto out_free;
@@ -5614,15 +5685,28 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                                       nla_data(ssid), nla_len(ssid));
                                request->match_sets[i].ssid.ssid_len =
                                        nla_len(ssid);
+                               /* special attribute - old implemenation w/a */
+                               request->match_sets[i].rssi_thold =
+                                       default_match_rssi;
+                               rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
+                               if (rssi)
+                                       request->match_sets[i].rssi_thold =
+                                               nla_get_s32(rssi);
                        }
-                       rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
-                       if (rssi)
-                               request->rssi_thold = nla_get_u32(rssi);
-                       else
-                               request->rssi_thold =
-                                                  NL80211_SCAN_RSSI_THOLD_OFF;
                        i++;
                }
+
+               /* there was no other matchset, so the RSSI one is alone */
+               if (i == 0)
+                       request->match_sets[0].rssi_thold = default_match_rssi;
+
+               request->min_rssi_thold = INT_MAX;
+               for (i = 0; i < n_match_sets; i++)
+                       request->min_rssi_thold =
+                               min(request->match_sets[i].rssi_thold,
+                                   request->min_rssi_thold);
+       } else {
+               request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
@@ -5718,7 +5802,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
 
        err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
        if (!err) {
-               wdev->channel = chandef.chan;
+               wdev->chandef = chandef;
                wdev->cac_started = true;
                wdev->cac_start_time = jiffies;
        }
@@ -5750,10 +5834,15 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 
                /* useless if AP is not running */
                if (!wdev->beacon_interval)
-                       return -EINVAL;
+                       return -ENOTCONN;
                break;
        case NL80211_IFTYPE_ADHOC:
+               if (!wdev->ssid_len)
+                       return -ENOTCONN;
+               break;
        case NL80211_IFTYPE_MESH_POINT:
+               if (!wdev->mesh_id_len)
+                       return -ENOTCONN;
                break;
        default:
                return -EOPNOTSUPP;
@@ -6191,9 +6280,9 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
-       chan = ieee80211_get_channel(&rdev->wiphy,
-               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+       chan = nl80211_get_valid_chan(&rdev->wiphy,
+                                     info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+       if (!chan)
                return -EINVAL;
 
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
@@ -6346,9 +6435,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       chan = ieee80211_get_channel(&rdev->wiphy,
-               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+       chan = nl80211_get_valid_chan(&rdev->wiphy,
+                                     info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+       if (!chan)
                return -EINVAL;
 
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
@@ -6984,6 +7073,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        if (info->attrs[NL80211_ATTR_MAC])
                connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       else if (info->attrs[NL80211_ATTR_MAC_HINT])
+               connect.bssid_hint =
+                       nla_data(info->attrs[NL80211_ATTR_MAC_HINT]);
        connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
@@ -7002,11 +7094,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               connect.channel =
-                       ieee80211_get_channel(wiphy,
-                           nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-               if (!connect.channel ||
-                   connect.channel->flags & IEEE80211_CHAN_DISABLED)
+               connect.channel = nl80211_get_valid_chan(
+                       wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+               if (!connect.channel)
+                       return -EINVAL;
+       } else if (info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]) {
+               connect.channel_hint = nl80211_get_valid_chan(
+                       wiphy, info->attrs[NL80211_ATTR_WIPHY_FREQ_HINT]);
+               if (!connect.channel_hint)
                        return -EINVAL;
        }
 
@@ -7420,6 +7515,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
        [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
                                .len = NL80211_MAX_SUPP_HT_RATES },
        [NL80211_TXRATE_VHT] = { .len = sizeof(struct nl80211_txrate_vht)},
+       [NL80211_TXRATE_GI] = { .type = NLA_U8 },
 };
 
 static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
@@ -7466,16 +7562,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
         * directly to the enum ieee80211_band values used in cfg80211.
         */
        BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
-       nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
-       {
+       nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
                enum ieee80211_band band = nla_type(tx_rates);
+               int err;
+
                if (band < 0 || band >= IEEE80211_NUM_BANDS)
                        return -EINVAL;
                sband = rdev->wiphy.bands[band];
                if (sband == NULL)
                        return -EINVAL;
-               nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
-                         nla_len(tx_rates), nl80211_txattr_policy);
+               err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
+                               nla_len(tx_rates), nl80211_txattr_policy);
+               if (err)
+                       return err;
                if (tb[NL80211_TXRATE_LEGACY]) {
                        mask.control[band].legacy = rateset_to_mask(
                                sband,
@@ -7500,6 +7599,12 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                                        mask.control[band].vht_mcs))
                                return -EINVAL;
                }
+               if (tb[NL80211_TXRATE_GI]) {
+                       mask.control[band].gi =
+                               nla_get_u8(tb[NL80211_TXRATE_GI]);
+                       if (mask.control[band].gi > NL80211_TXRATE_FORCE_LGI)
+                               return -EINVAL;
+               }
 
                if (mask.control[band].legacy == 0) {
                        /* don't allow empty legacy rates if HT or VHT
@@ -7776,8 +7881,8 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
-static struct nla_policy
-nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
+static const struct nla_policy
+nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
        [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
        [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
        [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
@@ -11115,7 +11220,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
                    wdev->iftype != NL80211_IFTYPE_MESH_POINT))
                return;
 
-       wdev->channel = chandef->chan;
+       wdev->chandef = *chandef;
+       wdev->preset_chandef = *chandef;
        nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
 }
 EXPORT_SYMBOL(cfg80211_ch_switch_notify);
@@ -11629,6 +11735,35 @@ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
 }
 EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
 
+void nl80211_send_ap_stopped(struct wireless_dev *wdev)
+{
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_STOP_AP);
+       if (!hdr)
+               goto out;
+
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
+           nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
+               goto out;
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(wiphy), msg, 0,
+                               NL80211_MCGRP_MLME, GFP_KERNEL);
+       return;
+ out:
+       nlmsg_free(msg);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
index b1b231324e102a44218bcf2354e52662fac78f5a..cb0216e1a0041b1c66b2a4a3e55405492b7743f7 100644 (file)
@@ -74,6 +74,8 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp);
 
+void nl80211_send_ap_stopped(struct wireless_dev *wdev);
+
 void cfg80211_rdev_free_coalesce(struct cfg80211_registered_device *rdev);
 
 #endif /* __NET_WIRELESS_NL80211_H */
index 9b897fca7487dd4fe8d8364368e8516ab8f369c0..27c5253e7a610b706ac99402727eda9bc66de755 100644 (file)
@@ -91,7 +91,7 @@ static struct regulatory_request __rcu *last_request =
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
 
-static struct device_type reg_device_type = {
+static const struct device_type reg_device_type = {
        .uevent = reg_device_uevent,
 };
 
@@ -522,6 +522,77 @@ bool reg_is_valid_request(const char *alpha2)
        return alpha2_equal(lr->alpha2, alpha2);
 }
 
+static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
+{
+       struct regulatory_request *lr = get_last_request();
+
+       /*
+        * Follow the driver's regulatory domain, if present, unless a country
+        * IE has been processed or a user wants to help complaince further
+        */
+       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+           lr->initiator != NL80211_REGDOM_SET_BY_USER &&
+           wiphy->regd)
+               return get_wiphy_regdom(wiphy);
+
+       return get_cfg80211_regdom();
+}
+
+unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
+                                  const struct ieee80211_reg_rule *rule)
+{
+       const struct ieee80211_freq_range *freq_range = &rule->freq_range;
+       const struct ieee80211_freq_range *freq_range_tmp;
+       const struct ieee80211_reg_rule *tmp;
+       u32 start_freq, end_freq, idx, no;
+
+       for (idx = 0; idx < rd->n_reg_rules; idx++)
+               if (rule == &rd->reg_rules[idx])
+                       break;
+
+       if (idx == rd->n_reg_rules)
+               return 0;
+
+       /* get start_freq */
+       no = idx;
+
+       while (no) {
+               tmp = &rd->reg_rules[--no];
+               freq_range_tmp = &tmp->freq_range;
+
+               if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz)
+                       break;
+
+               if (freq_range_tmp->max_bandwidth_khz)
+                       break;
+
+               freq_range = freq_range_tmp;
+       }
+
+       start_freq = freq_range->start_freq_khz;
+
+       /* get end_freq */
+       freq_range = &rule->freq_range;
+       no = idx;
+
+       while (no < rd->n_reg_rules - 1) {
+               tmp = &rd->reg_rules[++no];
+               freq_range_tmp = &tmp->freq_range;
+
+               if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz)
+                       break;
+
+               if (freq_range_tmp->max_bandwidth_khz)
+                       break;
+
+               freq_range = freq_range_tmp;
+       }
+
+       end_freq = freq_range->end_freq_khz;
+
+       return end_freq - start_freq;
+}
+
 /* Sanity check on a regulatory rule */
 static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
 {
@@ -630,7 +701,9 @@ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
  * Helper for regdom_intersect(), this does the real
  * mathematical intersection fun
  */
-static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
+static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
+                              const struct ieee80211_regdomain *rd2,
+                              const struct ieee80211_reg_rule *rule1,
                               const struct ieee80211_reg_rule *rule2,
                               struct ieee80211_reg_rule *intersected_rule)
 {
@@ -638,7 +711,7 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
        struct ieee80211_freq_range *freq_range;
        const struct ieee80211_power_rule *power_rule1, *power_rule2;
        struct ieee80211_power_rule *power_rule;
-       u32 freq_diff;
+       u32 freq_diff, max_bandwidth1, max_bandwidth2;
 
        freq_range1 = &rule1->freq_range;
        freq_range2 = &rule2->freq_range;
@@ -652,8 +725,24 @@ static int reg_rules_intersect(const struct ieee80211_reg_rule *rule1,
                                         freq_range2->start_freq_khz);
        freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
                                       freq_range2->end_freq_khz);
-       freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
-                                           freq_range2->max_bandwidth_khz);
+
+       max_bandwidth1 = freq_range1->max_bandwidth_khz;
+       max_bandwidth2 = freq_range2->max_bandwidth_khz;
+
+       /*
+        * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set
+        * output bandwidth as 0 (auto calculation). Next we will
+        * calculate this correctly in handle_channel function.
+        * In other case calculate output bandwidth here.
+        */
+       if (max_bandwidth1 || max_bandwidth2) {
+               if (!max_bandwidth1)
+                       max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1);
+               if (!max_bandwidth2)
+                       max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2);
+       }
+
+       freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2);
 
        freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
        if (freq_range->max_bandwidth_khz > freq_diff)
@@ -713,7 +802,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
                rule1 = &rd1->reg_rules[x];
                for (y = 0; y < rd2->n_reg_rules; y++) {
                        rule2 = &rd2->reg_rules[y];
-                       if (!reg_rules_intersect(rule1, rule2, &dummy_rule))
+                       if (!reg_rules_intersect(rd1, rd2, rule1, rule2,
+                                                &dummy_rule))
                                num_rules++;
                }
        }
@@ -738,7 +828,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
                         * a memcpy()
                         */
                        intersected_rule = &rd->reg_rules[rule_idx];
-                       r = reg_rules_intersect(rule1, rule2, intersected_rule);
+                       r = reg_rules_intersect(rd1, rd2, rule1, rule2,
+                                               intersected_rule);
                        /*
                         * No need to memset here the intersected rule here as
                         * we're not using the stack anymore
@@ -821,18 +912,8 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
                                               u32 center_freq)
 {
        const struct ieee80211_regdomain *regd;
-       struct regulatory_request *lr = get_last_request();
 
-       /*
-        * Follow the driver's regulatory domain, if present, unless a country
-        * IE has been processed or a user wants to help complaince further
-        */
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           lr->initiator != NL80211_REGDOM_SET_BY_USER &&
-           wiphy->regd)
-               regd = get_wiphy_regdom(wiphy);
-       else
-               regd = get_cfg80211_regdom();
+       regd = reg_get_regdomain(wiphy);
 
        return freq_reg_info_regd(wiphy, center_freq, regd);
 }
@@ -903,6 +984,8 @@ static void handle_channel(struct wiphy *wiphy,
        const struct ieee80211_freq_range *freq_range = NULL;
        struct wiphy *request_wiphy = NULL;
        struct regulatory_request *lr = get_last_request();
+       const struct ieee80211_regdomain *regd;
+       u32 max_bandwidth_khz;
 
        request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
 
@@ -944,11 +1027,18 @@ static void handle_channel(struct wiphy *wiphy,
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
 
-       if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
+       max_bandwidth_khz = freq_range->max_bandwidth_khz;
+       /* Check if auto calculation requested */
+       if (!max_bandwidth_khz) {
+               regd = reg_get_regdomain(wiphy);
+               max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
+       }
+
+       if (max_bandwidth_khz < MHZ_TO_KHZ(40))
                bw_flags = IEEE80211_CHAN_NO_HT40;
-       if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80))
+       if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
-       if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160))
+       if (max_bandwidth_khz < MHZ_TO_KHZ(160))
                bw_flags |= IEEE80211_CHAN_NO_160MHZ;
 
        if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
@@ -1334,6 +1424,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
        const struct ieee80211_reg_rule *reg_rule = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
        const struct ieee80211_freq_range *freq_range = NULL;
+       u32 max_bandwidth_khz;
 
        reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
                                      regd);
@@ -1351,11 +1442,16 @@ static void handle_channel_custom(struct wiphy *wiphy,
        power_rule = &reg_rule->power_rule;
        freq_range = &reg_rule->freq_range;
 
-       if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
+       max_bandwidth_khz = freq_range->max_bandwidth_khz;
+       /* Check if auto calculation requested */
+       if (!max_bandwidth_khz)
+               max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
+
+       if (max_bandwidth_khz < MHZ_TO_KHZ(40))
                bw_flags = IEEE80211_CHAN_NO_HT40;
-       if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(80))
+       if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
-       if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(160))
+       if (max_bandwidth_khz < MHZ_TO_KHZ(160))
                bw_flags |= IEEE80211_CHAN_NO_160MHZ;
 
        chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
@@ -1683,17 +1779,9 @@ static void reg_process_hint(struct regulatory_request *reg_request)
        struct wiphy *wiphy = NULL;
        enum reg_request_treatment treatment;
 
-       if (WARN_ON(!reg_request->alpha2))
-               return;
-
        if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)
                wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
 
-       if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {
-               kfree(reg_request);
-               return;
-       }
-
        switch (reg_request->initiator) {
        case NL80211_REGDOM_SET_BY_CORE:
                reg_process_hint_core(reg_request);
@@ -1703,23 +1791,33 @@ static void reg_process_hint(struct regulatory_request *reg_request)
                if (treatment == REG_REQ_OK ||
                    treatment == REG_REQ_ALREADY_SET)
                        return;
-               schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &reg_timeout, msecs_to_jiffies(3142));
                return;
        case NL80211_REGDOM_SET_BY_DRIVER:
+               if (!wiphy)
+                       goto out_free;
                treatment = reg_process_hint_driver(wiphy, reg_request);
                break;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               if (!wiphy)
+                       goto out_free;
                treatment = reg_process_hint_country_ie(wiphy, reg_request);
                break;
        default:
                WARN(1, "invalid initiator %d\n", reg_request->initiator);
-               return;
+               goto out_free;
        }
 
        /* This is required so that the orig_* parameters are saved */
        if (treatment == REG_REQ_ALREADY_SET && wiphy &&
            wiphy->regulatory_flags & REGULATORY_STRICT_REG)
                wiphy_update_regulatory(wiphy, reg_request->initiator);
+
+       return;
+
+out_free:
+       kfree(reg_request);
 }
 
 /*
@@ -2147,6 +2245,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
        const struct ieee80211_reg_rule *reg_rule = NULL;
        const struct ieee80211_freq_range *freq_range = NULL;
        const struct ieee80211_power_rule *power_rule = NULL;
+       char bw[32];
 
        pr_info("  (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n");
 
@@ -2155,22 +2254,29 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
                freq_range = &reg_rule->freq_range;
                power_rule = &reg_rule->power_rule;
 
+               if (!freq_range->max_bandwidth_khz)
+                       snprintf(bw, 32, "%d KHz, AUTO",
+                                reg_get_max_bandwidth(rd, reg_rule));
+               else
+                       snprintf(bw, 32, "%d KHz",
+                                freq_range->max_bandwidth_khz);
+
                /*
                 * There may not be documentation for max antenna gain
                 * in certain regions
                 */
                if (power_rule->max_antenna_gain)
-                       pr_info("  (%d KHz - %d KHz @ %d KHz), (%d mBi, %d mBm)\n",
+                       pr_info("  (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
-                               freq_range->max_bandwidth_khz,
+                               bw,
                                power_rule->max_antenna_gain,
                                power_rule->max_eirp);
                else
-                       pr_info("  (%d KHz - %d KHz @ %d KHz), (N/A, %d mBm)\n",
+                       pr_info("  (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n",
                                freq_range->start_freq_khz,
                                freq_range->end_freq_khz,
-                               freq_range->max_bandwidth_khz,
+                               bw,
                                power_rule->max_eirp);
        }
 }
@@ -2294,7 +2400,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
 
        request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
        if (!request_wiphy) {
-               schedule_delayed_work(&reg_timeout, 0);
+               queue_delayed_work(system_power_efficient_wq,
+                                  &reg_timeout, 0);
                return -ENODEV;
        }
 
@@ -2354,7 +2461,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
 
        request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx);
        if (!request_wiphy) {
-               schedule_delayed_work(&reg_timeout, 0);
+               queue_delayed_work(system_power_efficient_wq,
+                                  &reg_timeout, 0);
                return -ENODEV;
        }
 
index 02bd8f4b0921dafca98c4e1bc23b729045b036db..18524617ab62642d5b8cbd59644d7e2be2e4fede 100644 (file)
@@ -34,6 +34,8 @@ int __init regulatory_init(void);
 void regulatory_exit(void);
 
 int set_regdom(const struct ieee80211_regdomain *rd);
+unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
+                                  const struct ieee80211_reg_rule *rule);
 
 bool reg_last_request_cell_base(void);
 
index fbcc23edee5474459950b8566ecffd541ad4ed7d..5eaeed59db07651de6305320187f127c9fdd8b65 100644 (file)
@@ -2278,11 +2278,6 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt,
        TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr))
 );
 
-DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined,
-       TP_PROTO(struct net_device *netdev, const u8 *addr),
-       TP_ARGS(netdev, addr)
-);
-
 DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_spurious_frame,
        TP_PROTO(struct net_device *netdev, const u8 *addr),
        TP_ARGS(netdev, addr)
@@ -2293,6 +2288,24 @@ DEFINE_EVENT(cfg80211_rx_evt, cfg80211_rx_unexpected_4addr_frame,
        TP_ARGS(netdev, addr)
 );
 
+TRACE_EVENT(cfg80211_ibss_joined,
+       TP_PROTO(struct net_device *netdev, const u8 *bssid,
+                struct ieee80211_channel *channel),
+       TP_ARGS(netdev, bssid, channel),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               MAC_ENTRY(bssid)
+               CHAN_ENTRY
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(bssid, bssid);
+               CHAN_ASSIGN(channel);
+       ),
+       TP_printk(NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", " CHAN_PR_FMT,
+                 NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
+);
+
 TRACE_EVENT(cfg80211_probe_status,
        TP_PROTO(struct net_device *netdev, const u8 *addr, u64 cookie,
                 bool acked),
index d39c37104ae2f125c5def9c943dc65ab8a669f5a..780b4546c9c74c133d2de69ddcc352ca0979b8fe 100644 (file)
@@ -820,7 +820,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                                                ev->dc.reason, true);
                        break;
                case EVENT_IBSS_JOINED:
-                       __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
+                       __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
+                                              ev->ij.channel);
                        break;
                }
                wdev_unlock(wdev);
@@ -1356,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                 */
                mutex_lock_nested(&wdev_iter->mtx, 1);
                __acquire(wdev_iter->mtx);
-               cfg80211_get_chan_state(wdev_iter, &ch, &chmode);
+               cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect);
                wdev_unlock(wdev_iter);
 
                switch (chmode) {