Merge git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 4 Dec 2014 16:29:10 +0000 (11:29 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 4 Dec 2014 16:29:10 +0000 (11:29 -0500)
Johannes Berg <johannes@sipsolutions.net> says:

"This time I have Felix's no-status rate control work, which will allow
drivers to work better with rate control even if they don't have perfect
status reporting. In addition to this, a small hwsim fix from Patrik,
one of the regulatory patches from Arik, and a number of cleanups and
fixes I did myself.

Of note is a patch where I disable CFG80211_WEXT so that compatibility
is no longer selectable - this is intended as a wake-up call for anyone
who's still using it, and is still easily worked around (it's a one-line
patch) before we fully remove the code as well in the future."

Signed-off-by: John W. Linville <linville@tuxdriver.com>
21 files changed:
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/ti/wlcore/event.c
include/net/cfg80211.h
include/net/mac80211.h
include/net/regulatory.h
include/uapi/linux/nl80211.h
net/mac80211/chan.c
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/status.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/wireless/Kconfig
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/reg.c

index 2371d11e4190b718c21520305130d8bddb1c4bb5..a71b9d5e353d6d114c10d712b72f553f6edfe8ec 100644 (file)
@@ -2388,7 +2388,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
                sband->vht_cap.cap =
                        IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
                        IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
-                       IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
                        IEEE80211_VHT_CAP_RXLDPC |
                        IEEE80211_VHT_CAP_SHORT_GI_80 |
                        IEEE80211_VHT_CAP_SHORT_GI_160 |
@@ -2543,7 +2542,9 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb,
        if (cb)
                genl_dump_check_consistent(cb, hdr, &hwsim_genl_family);
 
-       param.reg_alpha2 = data->alpha2;
+       if (data->alpha2[0] && data->alpha2[1])
+               param.reg_alpha2 = data->alpha2;
+
        param.reg_strict = !!(data->hw->wiphy->regulatory_flags &
                                        REGULATORY_STRICT_REG);
        param.p2p_device = !!(data->hw->wiphy->interface_modes &
index 16d10281798d764ad8fb69f73cab6de0c2ff10d0..5153640f45323ac56eb9b662bdb08415e447562b 100644 (file)
@@ -259,10 +259,7 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
                                             &wlvif->connection_loss_work,
                                             msecs_to_jiffies(delay));
 
-               ieee80211_cqm_rssi_notify(
-                               vif,
-                               NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
-                               GFP_KERNEL);
+               ieee80211_cqm_beacon_loss_notify(vif, GFP_KERNEL);
        }
 }
 EXPORT_SYMBOL_GPL(wlcore_event_beacon_loss);
index bb748c4da5afdaff14cb8d6ed753a4cc155ace39..4ebb816241fa1ad76506d30265878cacb47b1aec 100644 (file)
@@ -4642,33 +4642,6 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
                              enum nl80211_cqm_rssi_threshold_event rssi_event,
                              gfp_t gfp);
 
-/**
- * cfg80211_radar_event - radar detection event
- * @wiphy: the wiphy
- * @chandef: chandef for the current channel
- * @gfp: context flags
- *
- * This function is called when a radar is detected on the current chanenl.
- */
-void cfg80211_radar_event(struct wiphy *wiphy,
-                         struct cfg80211_chan_def *chandef, gfp_t gfp);
-
-/**
- * cfg80211_cac_event - Channel availability check (CAC) event
- * @netdev: network device
- * @chandef: chandef for the current channel
- * @event: type of event
- * @gfp: context flags
- *
- * This function is called when a Channel availability check (CAC) is finished
- * or aborted. This must be called to notify the completion of a CAC process,
- * also by full-MAC drivers.
- */
-void cfg80211_cac_event(struct net_device *netdev,
-                       const struct cfg80211_chan_def *chandef,
-                       enum nl80211_radar_event event, gfp_t gfp);
-
-
 /**
  * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
  * @dev: network device
@@ -4696,6 +4669,42 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
                             u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
 
+/**
+ * cfg80211_cqm_beacon_loss_notify - beacon loss event
+ * @dev: network device
+ * @gfp: context flags
+ *
+ * Notify userspace about beacon loss from the connected AP.
+ */
+void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
+
+/**
+ * cfg80211_radar_event - radar detection event
+ * @wiphy: the wiphy
+ * @chandef: chandef for the current channel
+ * @gfp: context flags
+ *
+ * This function is called when a radar is detected on the current chanenl.
+ */
+void cfg80211_radar_event(struct wiphy *wiphy,
+                         struct cfg80211_chan_def *chandef, gfp_t gfp);
+
+/**
+ * cfg80211_cac_event - Channel availability check (CAC) event
+ * @netdev: network device
+ * @chandef: chandef for the current channel
+ * @event: type of event
+ * @gfp: context flags
+ *
+ * This function is called when a Channel availability check (CAC) is finished
+ * or aborted. This must be called to notify the completion of a CAC process,
+ * also by full-MAC drivers.
+ */
+void cfg80211_cac_event(struct net_device *netdev,
+                       const struct cfg80211_chan_def *chandef,
+                       enum nl80211_radar_event event, gfp_t gfp);
+
+
 /**
  * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
  * @dev: network device
index cff3a26a9dae0444d90b808fecdae1e1e387dd2d..58d719ddaa60c93d2c6424765e96abf254cb4dc6 100644 (file)
@@ -3618,6 +3618,26 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
 void ieee80211_tx_status(struct ieee80211_hw *hw,
                         struct sk_buff *skb);
 
+/**
+ * ieee80211_tx_status_noskb - transmit status callback without skb
+ *
+ * This function can be used as a replacement for ieee80211_tx_status
+ * in drivers that cannot reliably map tx status information back to
+ * specific skbs.
+ *
+ * Calls to this function for a single hardware must be synchronized
+ * against each other. Calls to this function, ieee80211_tx_status_ni()
+ * and ieee80211_tx_status_irqsafe() may not be mixed for a single hardware.
+ *
+ * @hw: the hardware the frame was transmitted by
+ * @sta: the receiver station to which this packet is sent
+ *     (NULL for multicast packets)
+ * @info: tx status information
+ */
+void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
+                              struct ieee80211_sta *sta,
+                              struct ieee80211_tx_info *info);
+
 /**
  * ieee80211_tx_status_ni - transmit status callback (in process context)
  *
@@ -4671,6 +4691,14 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
                               enum nl80211_cqm_rssi_threshold_event rssi_event,
                               gfp_t gfp);
 
+/**
+ * ieee80211_cqm_beacon_loss_notify - inform CQM of beacon loss
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @gfp: context flags
+ */
+void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp);
+
 /**
  * ieee80211_radar_detected - inform that a radar was detected
  *
@@ -4829,6 +4857,10 @@ struct rate_control_ops {
        void (*free_sta)(void *priv, struct ieee80211_sta *sta,
                         void *priv_sta);
 
+       void (*tx_status_noskb)(void *priv,
+                               struct ieee80211_supported_band *sband,
+                               struct ieee80211_sta *sta, void *priv_sta,
+                               struct ieee80211_tx_info *info);
        void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
                          struct ieee80211_sta *sta, void *priv_sta,
                          struct sk_buff *skb);
index dad7ab20a8cb204f08b2ecda724d5c1db5138ec8..b776d72d84be8f03fde9650c4b90d1b17940d543 100644 (file)
@@ -136,6 +136,17 @@ struct regulatory_request {
  *      otherwise initiating radiation is not allowed. This will enable the
  *      relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
  *      option
+ * @REGULATORY_IGNORE_STALE_KICKOFF: the regulatory core will _not_ make sure
+ *     all interfaces on this wiphy reside on allowed channels. If this flag
+ *     is not set, upon a regdomain change, the interfaces are given a grace
+ *     period (currently 60 seconds) to disconnect or move to an allowed
+ *     channel. Interfaces on forbidden channels are forcibly disconnected.
+ *     Currently these types of interfaces are supported for enforcement:
+ *     NL80211_IFTYPE_ADHOC, NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP,
+ *     NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_MONITOR,
+ *     NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO,
+ *     NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device
+ *     includes any modes unsupported for enforcement checking.
  */
 enum ieee80211_regulatory_flags {
        REGULATORY_CUSTOM_REG                   = BIT(0),
@@ -144,6 +155,7 @@ enum ieee80211_regulatory_flags {
        REGULATORY_COUNTRY_IE_FOLLOW_POWER      = BIT(3),
        REGULATORY_COUNTRY_IE_IGNORE            = BIT(4),
        REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
+       REGULATORY_IGNORE_STALE_KICKOFF         = BIT(6),
 };
 
 struct ieee80211_freq_range {
index d77524510435f47d6a8ca7c173fb13c394fc0f6f..b37bd5a1cb8253cd334ea05c3da920f0cf30f6e0 100644 (file)
@@ -3451,6 +3451,8 @@ enum nl80211_ps_state {
  *     interval in which %NL80211_ATTR_CQM_TXE_PKTS and
  *     %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
  *     %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
+ * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
+ *     loss event
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -3463,6 +3465,7 @@ enum nl80211_attr_cqm {
        NL80211_ATTR_CQM_TXE_RATE,
        NL80211_ATTR_CQM_TXE_PKTS,
        NL80211_ATTR_CQM_TXE_INTVL,
+       NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
 
        /* keep last */
        __NL80211_ATTR_CQM_AFTER_LAST,
@@ -3475,9 +3478,7 @@ enum nl80211_attr_cqm {
  *      configured threshold
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
- * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
- *     (Note that deauth/disassoc will still follow if the AP is not
- *     available. This event might get used as roaming event, etc.)
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
  */
 enum nl80211_cqm_rssi_threshold_event {
        NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
index c7c51422029822269762e40527a7ad44ddcbe991..5d6dae9e4aac099379e6ad8ed54d5ef40eac0f88 100644 (file)
@@ -932,6 +932,21 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
        }
 }
 
+static void
+ieee80211_vif_update_chandef(struct ieee80211_sub_if_data *sdata,
+                            const struct cfg80211_chan_def *chandef)
+{
+       struct ieee80211_sub_if_data *vlan;
+
+       sdata->vif.bss_conf.chandef = *chandef;
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
+               return;
+
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+               vlan->vif.bss_conf.chandef = *chandef;
+}
+
 static int
 ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
 {
@@ -994,7 +1009,7 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
        if (sdata->vif.bss_conf.chandef.width != sdata->reserved_chandef.width)
                changed = BSS_CHANGED_BANDWIDTH;
 
-       sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+       ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
 
        if (changed)
                ieee80211_bss_info_change_notify(sdata, changed);
@@ -1336,7 +1351,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                            sdata->reserved_chandef.width)
                                changed = BSS_CHANGED_BANDWIDTH;
 
-                       sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
+                       ieee80211_vif_update_chandef(sdata, &sdata->reserved_chandef);
                        if (changed)
                                ieee80211_bss_info_change_notify(sdata,
                                                                 changed);
@@ -1507,7 +1522,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
                goto out;
        }
 
-       sdata->vif.bss_conf.chandef = *chandef;
+       ieee80211_vif_update_chandef(sdata, chandef);
 
        ret = ieee80211_assign_vif_chanctx(sdata, ctx);
        if (ret) {
@@ -1649,7 +1664,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
                break;
        }
 
-       sdata->vif.bss_conf.chandef = *chandef;
+       ieee80211_vif_update_chandef(sdata, chandef);
 
        ieee80211_recalc_chanctx_chantype(local, ctx);
 
index 538fe4ef5c85dd7e285f8fb0f8166073cebcfac6..41735539087380c8e84735ef52efd1f2d265bbed 100644 (file)
@@ -520,6 +520,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                sdata->vif.cab_queue = master->vif.cab_queue;
                memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
                       sizeof(sdata->vif.hw_queue));
+               sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
                break;
                }
        case NL80211_IFTYPE_AP:
index ba06cd003375bf9592603823b8f452dd97a5ec63..75a9bf50207ecd6cdf5ac41cae7101d03ac58a11 100644 (file)
@@ -552,13 +552,17 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
        cap = vht_cap.cap;
 
        if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_80P80MHZ) {
-               cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
-               cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+               u32 bw = cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+
+               cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+               if (bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
+                   bw == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+                       cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
        }
 
        if (sdata->u.mgd.flags & IEEE80211_STA_DISABLE_160MHZ) {
                cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
-               cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+               cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
        }
 
        /*
@@ -2263,9 +2267,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
                                     "detected beacon loss from AP (missed %d beacons) - probing\n",
                                     beacon_loss_count);
 
-               ieee80211_cqm_rssi_notify(&sdata->vif,
-                                         NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
-                                         GFP_KERNEL);
+               ieee80211_cqm_beacon_loss_notify(&sdata->vif, GFP_KERNEL);
        }
 
        /*
@@ -4898,3 +4900,13 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
        cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
+
+void ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       trace_api_cqm_beacon_loss_notify(sdata->local, sdata);
+
+       cfg80211_cqm_beacon_loss_notify(sdata->dev, gfp);
+}
+EXPORT_SYMBOL(ieee80211_cqm_beacon_loss_notify);
index 08ab7d6d15173822d844e60f920e15b5ac94c1cc..d53355b011f5cf6407367e3c5f1a3e513d1cc08e 100644 (file)
@@ -446,7 +446,8 @@ static void rate_fixup_ratelist(struct ieee80211_vif *vif,
         *
         * XXX: Should this check all retry rates?
         */
-       if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) {
+       if (!(rates[0].flags &
+             (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) {
                u32 basic_rates = vif->bss_conf.basic_rates;
                s8 baserate = basic_rates ? ffs(basic_rates) - 1 : 0;
 
index 18babe30283212c18ddb113f3295d211a310d014..38652f09feaf250ec0517e23c8f147c8921f7499 100644 (file)
@@ -37,13 +37,35 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
        struct rate_control_ref *ref = local->rate_ctrl;
        struct ieee80211_sta *ista = &sta->sta;
        void *priv_sta = sta->rate_ctrl_priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
                return;
 
-       ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
+       if (ref->ops->tx_status)
+               ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
+       else
+               ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
 }
 
+static inline void
+rate_control_tx_status_noskb(struct ieee80211_local *local,
+                            struct ieee80211_supported_band *sband,
+                            struct sta_info *sta,
+                            struct ieee80211_tx_info *info)
+{
+       struct rate_control_ref *ref = local->rate_ctrl;
+       struct ieee80211_sta *ista = &sta->sta;
+       void *priv_sta = sta->rate_ctrl_priv;
+
+       if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
+               return;
+
+       if (WARN_ON_ONCE(!ref->ops->tx_status_noskb))
+               return;
+
+       ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
+}
 
 static inline void rate_control_rate_init(struct sta_info *sta)
 {
index c2b91bf47f6d8d0caa64a29fce45c3cf8f76a83b..d51f6b1c549b8c24929e46b57b96df639d5939ba 100644 (file)
@@ -223,11 +223,10 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
 static void
 minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
                   struct ieee80211_sta *sta, void *priv_sta,
-                  struct sk_buff *skb)
+                  struct ieee80211_tx_info *info)
 {
        struct minstrel_priv *mp = priv;
        struct minstrel_sta_info *mi = priv_sta;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *ar = info->status.rates;
        int i, ndx;
        int success;
@@ -674,7 +673,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta)
 
 const struct rate_control_ops mac80211_minstrel = {
        .name = "minstrel",
-       .tx_status = minstrel_tx_status,
+       .tx_status_noskb = minstrel_tx_status,
        .get_rate = minstrel_get_rate,
        .rate_init = minstrel_rate_init,
        .alloc = minstrel_alloc,
index 62ff7cfb27236aa994401395e609b5767ae3878b..b52996aca4f14736a07d9a2bcb768e1d15a15fa3 100644 (file)
@@ -709,11 +709,10 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
 static void
 minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
                       struct ieee80211_sta *sta, void *priv_sta,
-                      struct sk_buff *skb)
+                      struct ieee80211_tx_info *info)
 {
        struct minstrel_ht_sta_priv *msp = priv_sta;
        struct minstrel_ht_sta *mi = &msp->ht;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *ar = info->status.rates;
        struct minstrel_rate_stats *rate, *rate2;
        struct minstrel_priv *mp = priv;
@@ -721,7 +720,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
        int i;
 
        if (!msp->is_ht)
-               return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
+               return mac80211_minstrel.tx_status_noskb(priv, sband, sta,
+                                                        &msp->legacy, info);
 
        /* This packet was aggregated but doesn't carry status info */
        if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
@@ -782,9 +782,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
        if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
                update = true;
                minstrel_ht_update_stats(mp, mi);
-               if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
-                   mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
-                       minstrel_aggr_check(sta, skb);
        }
 
        if (update)
@@ -1026,6 +1023,10 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        if (!msp->is_ht)
                return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
 
+       if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
+               minstrel_aggr_check(sta, txrc->skb);
+
        info->flags |= mi->tx_flags;
        minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
 
@@ -1342,7 +1343,7 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
 
 static const struct rate_control_ops mac80211_minstrel_ht = {
        .name = "minstrel_ht",
-       .tx_status = minstrel_ht_tx_status,
+       .tx_status_noskb = minstrel_ht_tx_status,
        .get_rate = minstrel_ht_get_rate,
        .rate_init = minstrel_ht_rate_init,
        .rate_update = minstrel_ht_rate_update,
index 71de2d3866cc08392687fefe8dd59abe9b36b064..bb146f377ee457e66a2f85cc99c264746bcace81 100644 (file)
@@ -592,10 +592,9 @@ static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
 #define STA_LOST_TDLS_PKT_THRESHOLD    10
 #define STA_LOST_TDLS_PKT_TIME         (10*HZ) /* 10secs since last ACK */
 
-static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
+static void ieee80211_lost_packet(struct sta_info *sta,
+                                 struct ieee80211_tx_info *info)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
        /* This packet was aggregated but doesn't carry status info */
        if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
            !(info->flags & IEEE80211_TX_STAT_AMPDU))
@@ -622,24 +621,13 @@ static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
        sta->lost_packets = 0;
 }
 
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
+                                 struct ieee80211_tx_info *info,
+                                 int *retry_count)
 {
-       struct sk_buff *skb2;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       __le16 fc;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_sub_if_data *sdata;
-       struct net_device *prev_dev = NULL;
-       struct sta_info *sta, *tmp;
-       int retry_count = -1, i;
        int rates_idx = -1;
-       bool send_to_cooked;
-       bool acked;
-       struct ieee80211_bar *bar;
-       int rtap_len;
-       int shift = 0;
+       int count = -1;
+       int i;
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
                if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
@@ -657,12 +645,91 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        break;
                }
 
-               retry_count += info->status.rates[i].count;
+               count += info->status.rates[i].count;
        }
        rates_idx = i - 1;
 
-       if (retry_count < 0)
-               retry_count = 0;
+       if (count < 0)
+               count = 0;
+
+       *retry_count = count;
+       return rates_idx;
+}
+
+void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
+                              struct ieee80211_sta *pubsta,
+                              struct ieee80211_tx_info *info)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_supported_band *sband;
+       int retry_count;
+       int rates_idx;
+       bool acked;
+
+       rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
+
+       sband = hw->wiphy->bands[info->band];
+
+       acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
+       if (pubsta) {
+               struct sta_info *sta;
+
+               sta = container_of(pubsta, struct sta_info, sta);
+
+               if (!acked)
+                       sta->tx_retry_failed++;
+               sta->tx_retry_count += retry_count;
+
+               if (acked) {
+                       sta->last_rx = jiffies;
+
+                       if (sta->lost_packets)
+                               sta->lost_packets = 0;
+
+                       /* Track when last TDLS packet was ACKed */
+                       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+                               sta->last_tdls_pkt_time = jiffies;
+               } else {
+                       ieee80211_lost_packet(sta, info);
+               }
+
+               rate_control_tx_status_noskb(local, sband, sta, info);
+       }
+
+       if (acked) {
+                   local->dot11TransmittedFrameCount++;
+                   if (!pubsta)
+                           local->dot11MulticastTransmittedFrameCount++;
+                   if (retry_count > 0)
+                           local->dot11RetryCount++;
+                   if (retry_count > 1)
+                           local->dot11MultipleRetryCount++;
+       } else {
+               local->dot11FailedCount++;
+       }
+}
+EXPORT_SYMBOL(ieee80211_tx_status_noskb);
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct sk_buff *skb2;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       __le16 fc;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_sub_if_data *sdata;
+       struct net_device *prev_dev = NULL;
+       struct sta_info *sta, *tmp;
+       int retry_count;
+       int rates_idx;
+       bool send_to_cooked;
+       bool acked;
+       struct ieee80211_bar *bar;
+       int rtap_len;
+       int shift = 0;
+
+       rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
 
        rcu_read_lock();
 
@@ -767,7 +834,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
                                        sta->last_tdls_pkt_time = jiffies;
                        } else {
-                               ieee80211_lost_packet(sta, skb);
+                               ieee80211_lost_packet(sta, info);
                        }
                }
 
index 85ccfbe863db12b3cbec43dba001a7a4d3bbe143..8e461a02c6a8ed9f8851979eed7992262704f60a 100644 (file)
@@ -1829,6 +1829,12 @@ TRACE_EVENT(api_cqm_rssi_notify,
        )
 );
 
+DEFINE_EVENT(local_sdata_evt, api_cqm_beacon_loss_notify,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
 TRACE_EVENT(api_scan_completed,
        TP_PROTO(struct ieee80211_local *local, bool aborted),
 
index 66ddbbeccd20c1e6eba9ec44a046f29ca331dbda..058686a721a1de5e1145da56d3f176d1e08ed739 100644 (file)
@@ -60,7 +60,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
        rcu_read_unlock();
 
        /* assume HW handles this */
-       if (tx->rate.flags & IEEE80211_TX_RC_MCS)
+       if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
                return 0;
 
        /* uh huh? */
index bb9664cb8831e337e3567dd32515f2593b641816..974ebe70f5b0139c0dd2aec7335201dec51e6aca 100644 (file)
@@ -1339,6 +1339,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
        int ext_rates_len;
        int shift;
        u32 rate_flags;
+       bool have_80mhz = false;
 
        *offset = 0;
 
@@ -1467,7 +1468,15 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
                *offset = noffset;
        }
 
-       if (sband->vht_cap.vht_supported) {
+       /* Check if any channel in this sband supports at least 80 MHz */
+       for (i = 0; i < sband->n_channels; i++) {
+               if (!(sband->channels[i].flags & IEEE80211_CHAN_NO_80MHZ)) {
+                       have_80mhz = true;
+                       break;
+               }
+       }
+
+       if (sband->vht_cap.vht_supported && have_80mhz) {
                if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
                        goto out_err;
                pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
index 29c8675f9a1189db65c185f2ad04f96a67702989..22ba971741e5c998c5f314e083ceead4b2f6a94f 100644 (file)
@@ -175,7 +175,7 @@ config CFG80211_INTERNAL_REGDB
          Most distributions have a CRDA package.  So if unsure, say N.
 
 config CFG80211_WEXT
-       bool "cfg80211 wireless extensions compatibility"
+       bool
        depends on CFG80211
        select WEXT_CORE
        help
index 4c2e501203d175578287d97d544aa0639f3ddf2e..53dda7728f866dd3e7df234a242668c5dbe04f20 100644 (file)
@@ -546,6 +546,20 @@ int wiphy_register(struct wiphy *wiphy)
                     !rdev->ops->tdls_cancel_channel_switch)))
                return -EINVAL;
 
+       /*
+        * if a wiphy has unsupported modes for regulatory channel enforcement,
+        * opt-out of enforcement checking
+        */
+       if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) |
+                                      BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                                      BIT(NL80211_IFTYPE_AP) |
+                                      BIT(NL80211_IFTYPE_P2P_GO) |
+                                      BIT(NL80211_IFTYPE_ADHOC) |
+                                      BIT(NL80211_IFTYPE_P2P_DEVICE) |
+                                      BIT(NL80211_IFTYPE_AP_VLAN) |
+                                      BIT(NL80211_IFTYPE_MONITOR)))
+               wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
+
        if (WARN_ON(wiphy->coalesce &&
                    (!wiphy->coalesce->n_rules ||
                     !wiphy->coalesce->n_patterns) &&
index 6e4177701d86fd847ab8bf933cca7c996f03b272..a17d6bc6b22ca7ccda9716af9a3367b66bc47632 100644 (file)
@@ -2317,7 +2317,8 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
 static int nl80211_send_chandef(struct sk_buff *msg,
                                const struct cfg80211_chan_def *chandef)
 {
-       WARN_ON(!cfg80211_chandef_valid(chandef));
+       if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+               return -EINVAL;
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
                        chandef->chan->center_freq))
@@ -5421,11 +5422,11 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
        struct nlattr *nl_reg_rule;
-       char *alpha2 = NULL;
-       int rem_reg_rules = 0, r = 0;
+       char *alpha2;
+       int rem_reg_rules, r;
        u32 num_rules = 0, rule_idx = 0, size_of_regd;
        enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
-       struct ieee80211_regdomain *rd = NULL;
+       struct ieee80211_regdomain *rd;
 
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
                return -EINVAL;
@@ -6562,8 +6563,6 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        }
 
        while (1) {
-               struct ieee80211_channel *chan;
-
                res = rdev_dump_survey(rdev, wdev->netdev, survey_idx, &survey);
                if (res == -ENOENT)
                        break;
@@ -6576,9 +6575,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                        goto out;
                }
 
-               chan = ieee80211_get_channel(&rdev->wiphy,
-                                            survey.channel->center_freq);
-               if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+               if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
                        survey_idx++;
                        continue;
                }
@@ -11770,55 +11767,155 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 }
 EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
 
-void cfg80211_cqm_rssi_notify(struct net_device *dev,
-                             enum nl80211_cqm_rssi_threshold_event rssi_event,
-                             gfp_t gfp)
+static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
+                                           const char *mac, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-       struct sk_buff *msg;
-       struct nlattr *pinfoattr;
-       void *hdr;
-
-       trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       void **cb;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
-               return;
+               return NULL;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
-       if (!hdr) {
+       cb = (void **)msg->cb;
+
+       cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
+       if (!cb[0]) {
                nlmsg_free(msg);
-               return;
+               return NULL;
        }
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
            nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
                goto nla_put_failure;
 
-       pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
-       if (!pinfoattr)
+       if (mac && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
                goto nla_put_failure;
 
-       if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
-                       rssi_event))
+       cb[1] = nla_nest_start(msg, NL80211_ATTR_CQM);
+       if (!cb[1])
                goto nla_put_failure;
 
-       nla_nest_end(msg, pinfoattr);
+       cb[2] = rdev;
 
-       genlmsg_end(msg, hdr);
+       return msg;
+ nla_put_failure:
+       nlmsg_free(msg);
+       return NULL;
+}
+
+static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
+{
+       void **cb = (void **)msg->cb;
+       struct cfg80211_registered_device *rdev = cb[2];
+
+       nla_nest_end(msg, cb[1]);
+       genlmsg_end(msg, cb[0]);
+
+       memset(msg->cb, 0, sizeof(msg->cb));
 
        genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
                                NL80211_MCGRP_MLME, gfp);
+}
+
+void cfg80211_cqm_rssi_notify(struct net_device *dev,
+                             enum nl80211_cqm_rssi_threshold_event rssi_event,
+                             gfp_t gfp)
+{
+       struct sk_buff *msg;
+
+       trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+
+       if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
+                   rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
+               return;
+
+       msg = cfg80211_prepare_cqm(dev, NULL, gfp);
+       if (!msg)
+               return;
+
+       if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+                       rssi_event))
+               goto nla_put_failure;
+
+       cfg80211_send_cqm(msg, gfp);
+
        return;
 
  nla_put_failure:
-       genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
 EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
 
+void cfg80211_cqm_txe_notify(struct net_device *dev,
+                            const u8 *peer, u32 num_packets,
+                            u32 rate, u32 intvl, gfp_t gfp)
+{
+       struct sk_buff *msg;
+
+       msg = cfg80211_prepare_cqm(dev, peer, gfp);
+       if (!msg)
+               return;
+
+       if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
+               goto nla_put_failure;
+
+       if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
+               goto nla_put_failure;
+
+       if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
+               goto nla_put_failure;
+
+       cfg80211_send_cqm(msg, gfp);
+       return;
+
+ nla_put_failure:
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
+
+void cfg80211_cqm_pktloss_notify(struct net_device *dev,
+                                const u8 *peer, u32 num_packets, gfp_t gfp)
+{
+       struct sk_buff *msg;
+
+       trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
+
+       msg = cfg80211_prepare_cqm(dev, peer, gfp);
+       if (!msg)
+               return;
+
+       if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
+               goto nla_put_failure;
+
+       cfg80211_send_cqm(msg, gfp);
+       return;
+
+ nla_put_failure:
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
+
+void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp)
+{
+       struct sk_buff *msg;
+
+       msg = cfg80211_prepare_cqm(dev, NULL, gfp);
+       if (!msg)
+               return;
+
+       if (nla_put_flag(msg, NL80211_ATTR_CQM_BEACON_LOSS_EVENT))
+               goto nla_put_failure;
+
+       cfg80211_send_cqm(msg, gfp);
+       return;
+
+ nla_put_failure:
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_cqm_beacon_loss_notify);
+
 static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
                                     struct net_device *netdev, const u8 *bssid,
                                     const u8 *replay_ctr, gfp_t gfp)
@@ -12007,59 +12104,6 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
 }
 EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
 
-void cfg80211_cqm_txe_notify(struct net_device *dev,
-                            const u8 *peer, u32 num_packets,
-                            u32 rate, u32 intvl, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-       struct sk_buff *msg;
-       struct nlattr *pinfoattr;
-       void *hdr;
-
-       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
-       if (!msg)
-               return;
-
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
-       if (!hdr) {
-               nlmsg_free(msg);
-               return;
-       }
-
-       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
-           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
-               goto nla_put_failure;
-
-       pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
-       if (!pinfoattr)
-               goto nla_put_failure;
-
-       if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
-               goto nla_put_failure;
-
-       if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
-               goto nla_put_failure;
-
-       if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
-               goto nla_put_failure;
-
-       nla_nest_end(msg, pinfoattr);
-
-       genlmsg_end(msg, hdr);
-
-       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-                               NL80211_MCGRP_MLME, gfp);
-       return;
-
- nla_put_failure:
-       genlmsg_cancel(msg, hdr);
-       nlmsg_free(msg);
-}
-EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
-
 void
 nl80211_radar_notify(struct cfg80211_registered_device *rdev,
                     const struct cfg80211_chan_def *chandef,
@@ -12108,54 +12152,6 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
-void cfg80211_cqm_pktloss_notify(struct net_device *dev,
-                                const u8 *peer, u32 num_packets, gfp_t gfp)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-       struct sk_buff *msg;
-       struct nlattr *pinfoattr;
-       void *hdr;
-
-       trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
-
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
-       if (!msg)
-               return;
-
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
-       if (!hdr) {
-               nlmsg_free(msg);
-               return;
-       }
-
-       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
-           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
-               goto nla_put_failure;
-
-       pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
-       if (!pinfoattr)
-               goto nla_put_failure;
-
-       if (nla_put_u32(msg, NL80211_ATTR_CQM_PKT_LOSS_EVENT, num_packets))
-               goto nla_put_failure;
-
-       nla_nest_end(msg, pinfoattr);
-
-       genlmsg_end(msg, hdr);
-
-       genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-                               NL80211_MCGRP_MLME, gfp);
-       return;
-
- nla_put_failure:
-       genlmsg_cancel(msg, hdr);
-       nlmsg_free(msg);
-}
-EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
-
 void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
                           u64 cookie, bool acked, gfp_t gfp)
 {
index 32d8310b0f8571201032b585d2c52fc26ad4f39d..47be6163381caadf41afab40122d74f4a19448e6 100644 (file)
@@ -56,6 +56,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
+#include "rdev-ops.h"
 #include "regdb.h"
 #include "nl80211.h"
 
 #define REG_DBG_PRINT(args...)
 #endif
 
+/*
+ * Grace period we give before making sure all current interfaces reside on
+ * channels allowed by the current regulatory domain.
+ */
+#define REG_ENFORCE_GRACE_MS 60000
+
 /**
  * enum reg_request_treatment - regulatory request treatment
  *
@@ -210,6 +217,9 @@ struct reg_beacon {
        struct ieee80211_channel chan;
 };
 
+static void reg_check_chans_work(struct work_struct *work);
+static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
+
 static void reg_todo(struct work_struct *work);
 static DECLARE_WORK(reg_work, reg_todo);
 
@@ -1518,6 +1528,96 @@ static void reg_call_notifier(struct wiphy *wiphy,
                wiphy->reg_notifier(wiphy, request);
 }
 
+static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+       struct ieee80211_channel *ch;
+       struct cfg80211_chan_def chandef;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+       bool ret = true;
+
+       wdev_lock(wdev);
+
+       if (!wdev->netdev || !netif_running(wdev->netdev))
+               goto out;
+
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+               if (!wdev->beacon_interval)
+                       goto out;
+
+               ret = cfg80211_reg_can_beacon(wiphy,
+                                             &wdev->chandef, wdev->iftype);
+               break;
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_ADHOC:
+               if (!wdev->current_bss ||
+                   !wdev->current_bss->pub.channel)
+                       goto out;
+
+               ch = wdev->current_bss->pub.channel;
+               if (rdev->ops->get_channel &&
+                   !rdev_get_channel(rdev, wdev, &chandef))
+                       ret = cfg80211_chandef_usable(wiphy, &chandef,
+                                                     IEEE80211_CHAN_DISABLED);
+               else
+                       ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
+               break;
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_DEVICE:
+               /* no enforcement required */
+               break;
+       default:
+               /* others not implemented for now */
+               WARN_ON(1);
+               break;
+       }
+
+out:
+       wdev_unlock(wdev);
+       return ret;
+}
+
+static void reg_leave_invalid_chans(struct wiphy *wiphy)
+{
+       struct wireless_dev *wdev;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+       ASSERT_RTNL();
+
+       list_for_each_entry(wdev, &rdev->wdev_list, list)
+               if (!reg_wdev_chan_valid(wiphy, wdev))
+                       cfg80211_leave(rdev, wdev);
+}
+
+static void reg_check_chans_work(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev;
+
+       REG_DBG_PRINT("Verifying active interfaces after reg change\n");
+       rtnl_lock();
+
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+               if (!(rdev->wiphy.regulatory_flags &
+                     REGULATORY_IGNORE_STALE_KICKOFF))
+                       reg_leave_invalid_chans(&rdev->wiphy);
+
+       rtnl_unlock();
+}
+
+static void reg_check_channels(void)
+{
+       /*
+        * Give usermode a chance to do something nicer (move to another
+        * channel, orderly disconnection), before forcing a disconnection.
+        */
+       mod_delayed_work(system_power_efficient_wq,
+                        &reg_check_chans,
+                        msecs_to_jiffies(REG_ENFORCE_GRACE_MS));
+}
+
 static void wiphy_update_regulatory(struct wiphy *wiphy,
                                    enum nl80211_reg_initiator initiator)
 {
@@ -1557,6 +1657,8 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
                wiphy = &rdev->wiphy;
                wiphy_update_regulatory(wiphy, initiator);
        }
+
+       reg_check_channels();
 }
 
 static void handle_channel_custom(struct wiphy *wiphy,
@@ -1976,8 +2078,10 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 
        /* This is required so that the orig_* parameters are saved */
        if (treatment == REG_REQ_ALREADY_SET && wiphy &&
-           wiphy->regulatory_flags & REGULATORY_STRICT_REG)
+           wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
                wiphy_update_regulatory(wiphy, reg_request->initiator);
+               reg_check_channels();
+       }
 
        return;
 
@@ -2858,6 +2962,7 @@ void regulatory_exit(void)
 
        cancel_work_sync(&reg_work);
        cancel_delayed_work_sync(&reg_timeout);
+       cancel_delayed_work_sync(&reg_check_chans);
 
        /* Lock to suppress warnings */
        rtnl_lock();