Merge branch 'mac80211' into mac80211-next
authorJohannes Berg <johannes.berg@intel.com>
Mon, 20 Oct 2014 14:41:33 +0000 (16:41 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 20 Oct 2014 19:39:29 +0000 (21:39 +0200)
This was needed to avoid conflicts in the minstrel changes.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
30 files changed:
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/ti/wlcore/main.c
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.h
net/mac80211/mesh_pathtbl.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/trace.h
net/mac80211/util.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/sme.c
net/wireless/trace.h

index ba60e37..7a53378 100644 (file)
@@ -2976,11 +2976,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
-                             const u8 *mac)
+                             struct station_del_parameters *params)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
-       const u8 *addr = mac ? mac : bcast_addr;
+       const u8 *addr = params->mac ? params->mac : bcast_addr;
 
        return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
                                      addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
index d9f4b30..8fdfa32 100644 (file)
@@ -792,12 +792,13 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
 }
 
 static int wil_cfg80211_del_station(struct wiphy *wiphy,
-                                   struct net_device *dev, const u8 *mac)
+                                   struct net_device *dev,
+                                   struct station_del_parameters *params)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, mac);
+       wil6210_disconnect(wil, params->mac);
        mutex_unlock(&wil->mutex);
 
        return 0;
index 28fa25b..1a2e062 100644 (file)
@@ -3998,24 +3998,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
 
 static int
 brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
-                          const u8 *mac)
+                          struct station_del_parameters *params)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_scb_val_le scbval;
        struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err;
 
-       if (!mac)
+       if (!params->mac)
                return -EFAULT;
 
-       brcmf_dbg(TRACE, "Enter %pM\n", mac);
+       brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
 
        if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
                ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
        if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       memcpy(&scbval.ea, mac, ETH_ALEN);
+       memcpy(&scbval.ea, params->mac, ETH_ALEN);
        scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
        err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
                                     &scbval, sizeof(scbval));
index 26fec54..2748fde 100644 (file)
@@ -6063,7 +6063,7 @@ il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 }
 
 void
-il4965_mac_channel_switch(struct ieee80211_hw *hw,
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                          struct ieee80211_channel_switch *ch_switch)
 {
        struct il_priv *il = hw->priv;
index 337dfcf..3a57f71 100644 (file)
@@ -187,8 +187,9 @@ int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            u8 buf_size);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
-void il4965_mac_channel_switch(struct ieee80211_hw *hw,
-                              struct ieee80211_channel_switch *ch_switch);
+void
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                         struct ieee80211_channel_switch *ch_switch);
 
 void il4965_led_enable(struct il_priv *il);
 
index 2364a3c..a967bf8 100644 (file)
@@ -941,6 +941,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
 }
 
 static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
                                      struct ieee80211_channel_switch *ch_switch)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
index babbdc1..6ffe073 100644 (file)
@@ -412,6 +412,9 @@ struct mac80211_hwsim_data {
        struct mac_address addresses[2];
        int channels, idx;
        bool use_chanctx;
+       bool destroy_on_close;
+       struct work_struct destroy_work;
+       u32 portid;
 
        struct ieee80211_channel *tmp_chan;
        struct delayed_work roc_done;
@@ -436,7 +439,7 @@ struct mac80211_hwsim_data {
        /*
         * Only radios in the same group can communicate together (the
         * channel has to match too). Each bit represents a group. A
-        * radio can be in more then one group.
+        * radio can be in more than one group.
         */
        u64 group;
 
@@ -496,6 +499,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
        [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
        [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
+       [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -862,7 +866,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
                /* Droping until WARN_QUEUE level */
                while (skb_queue_len(&data->pending) >= WARN_QUEUE)
-                       skb_dequeue(&data->pending);
+                       ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
        }
 
        skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
@@ -921,6 +925,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
 
 nla_put_failure:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
+       ieee80211_free_txskb(hw, my_skb);
 }
 
 static bool hwsim_chans_compat(struct ieee80211_channel *c1,
@@ -1946,7 +1951,8 @@ 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 p2p_device,
-                                      bool use_chanctx)
+                                      bool use_chanctx, bool destroy_on_close,
+                                      u32 portid)
 {
        int err;
        u8 addr[ETH_ALEN];
@@ -2006,6 +2012,8 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        data->channels = channels;
        data->use_chanctx = use_chanctx;
        data->idx = idx;
+       data->destroy_on_close = destroy_on_close;
+       data->portid = portid;
 
        if (data->use_chanctx) {
                hw->wiphy->max_scan_ssids = 255;
@@ -2391,7 +2399,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
        return 0;
 err:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
-       goto out;
 out:
        dev_kfree_skb(skb);
        return -EINVAL;
@@ -2434,6 +2441,7 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
        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];
+       bool destroy_on_close = info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
        bool use_chanctx;
 
        if (info->attrs[HWSIM_ATTR_CHANNELS])
@@ -2456,7 +2464,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
        }
 
        return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
-                                          p2p_device, use_chanctx);
+                                          p2p_device, use_chanctx,
+                                          destroy_on_close, info->snd_portid);
 }
 
 static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2514,6 +2523,29 @@ static const struct genl_ops hwsim_ops[] = {
        },
 };
 
+static void destroy_radio(struct work_struct *work)
+{
+       struct mac80211_hwsim_data *data =
+               container_of(work, struct mac80211_hwsim_data, destroy_work);
+
+       mac80211_hwsim_destroy_radio(data);
+}
+
+static void remove_user_radios(u32 portid)
+{
+       struct mac80211_hwsim_data *entry, *tmp;
+
+       spin_lock_bh(&hwsim_radio_lock);
+       list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
+               if (entry->destroy_on_close && entry->portid == portid) {
+                       list_del(&entry->list);
+                       INIT_WORK(&entry->destroy_work, destroy_radio);
+                       schedule_work(&entry->destroy_work);
+               }
+       }
+       spin_unlock_bh(&hwsim_radio_lock);
+}
+
 static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
                                         unsigned long state,
                                         void *_notify)
@@ -2523,6 +2555,8 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
        if (state != NETLINK_URELEASE)
                return NOTIFY_DONE;
 
+       remove_user_radios(notify->portid);
+
        if (notify->portid == wmediumd_portid) {
                printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
                       " socket, switching to perfect channel medium\n");
@@ -2676,7 +2710,7 @@ static int __init init_mac80211_hwsim(void)
                err = mac80211_hwsim_create_radio(channels, reg_alpha2,
                                                  regd, reg_strict,
                                                  support_p2p_device,
-                                                 channels > 1);
+                                                 channels > 1, false, 0);
                if (err < 0)
                        goto out_free_radios;
        }
index c9d0315..b96d867 100644 (file)
@@ -111,6 +111,8 @@ enum {
  * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
  *     command to force use of channel contexts even when only a
  *     single channel is supported
+ * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO
+ *     command to force radio removal when process that created the radio dies
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -132,6 +134,7 @@ enum {
        HWSIM_ATTR_REG_STRICT_REG,
        HWSIM_ATTR_SUPPORT_P2P_DEVICE,
        HWSIM_ATTR_USE_CHANCTX,
+       HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
        __HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
index 0dd6729..71e29c7 100644 (file)
@@ -1239,7 +1239,7 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
  */
 static int
 mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                            const u8 *mac)
+                            struct station_del_parameters *params)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        struct mwifiex_sta_node *sta_node;
@@ -1248,7 +1248,7 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (list_empty(&priv->sta_list) || !priv->bss_started)
                return 0;
 
-       if (!mac || is_broadcast_ether_addr(mac)) {
+       if (!params->mac || is_broadcast_ether_addr(params->mac)) {
                wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);
                list_for_each_entry(sta_node, &priv->sta_list, list) {
                        if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
@@ -1258,9 +1258,10 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
                        mwifiex_uap_del_sta_data(priv, sta_node);
                }
        } else {
-               wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, mac);
+               wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__,
+                         params->mac);
                spin_lock_irqsave(&priv->sta_list_spinlock, flags);
-               sta_node = mwifiex_get_sta_entry(priv, mac);
+               sta_node = mwifiex_get_sta_entry(priv, params->mac);
                spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
                if (sta_node) {
                        if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
index 575c8f6..6ad3fce 100644 (file)
@@ -5177,10 +5177,11 @@ out:
 }
 
 static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_channel_switch *ch_switch)
 {
        struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
@@ -5190,14 +5191,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
        mutex_lock(&wl->mutex);
 
        if (unlikely(wl->state == WLCORE_STATE_OFF)) {
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
-                       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                               continue;
-
+               if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
                        ieee80211_chswitch_done(vif, false);
-               }
                goto out;
        } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
                goto out;
@@ -5208,11 +5203,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
                goto out;
 
        /* TODO: change mac80211 to pass vif as param */
-       wl12xx_for_each_wlvif_sta(wl, wlvif) {
-               unsigned long delay_usec;
 
-               if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                       continue;
+       if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
+               unsigned long delay_usec;
 
                ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
                if (ret)
@@ -5222,10 +5215,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
                /* indicate failure 5 seconds after channel switch time */
                delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
-                            ch_switch->count;
+                       ch_switch->count;
                ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
-                               usecs_to_jiffies(delay_usec) +
-                               msecs_to_jiffies(5000));
+                                            usecs_to_jiffies(delay_usec) +
+                                            msecs_to_jiffies(5000));
        }
 
 out_sleep:
index bd6953a..3d26955 100644 (file)
@@ -2856,8 +2856,10 @@ static int cfg80211_rtw_add_station(struct wiphy *wiphy,
 }
 
 static int cfg80211_rtw_del_station(struct wiphy *wiphy,
-                                   struct net_device *ndev, const u8 *mac)
+                                   struct net_device *ndev,
+                                   struct station_del_parameters *params)
 {
+       const u8 *mac = params->mac;
        int ret = 0;
        struct list_head *phead, *plist, *ptmp;
        u8 updated = 0;
index b1be39c..5fab17b 100644 (file)
@@ -1998,6 +1998,11 @@ enum ieee80211_tdls_actioncode {
        WLAN_TDLS_DISCOVERY_REQUEST = 10,
 };
 
+/* Extended Channel Switching capability to be set in the 1st byte of
+ * the @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING   BIT(2)
+
 /* Interworking capabilities are set in 7th bit of 4th byte of the
  * @WLAN_EID_EXT_CAPABILITY information element
  */
index a2ddcf2..ed896c0 100644 (file)
@@ -798,6 +798,22 @@ struct station_parameters {
        bool opmode_notif_used;
 };
 
+/**
+ * struct station_del_parameters - station deletion parameters
+ *
+ * Used to delete a station entry (or all stations).
+ *
+ * @mac: MAC address of the station to remove or NULL to remove all stations
+ * @subtype: Management frame subtype to use for indicating removal
+ *     (10 = Disassociation, 12 = Deauthentication)
+ * @reason_code: Reason code for the Disassociation/Deauthentication frame
+ */
+struct station_del_parameters {
+       const u8 *mac;
+       u8 subtype;
+       u16 reason_code;
+};
+
 /**
  * enum cfg80211_station_type - the type of station being modified
  * @CFG80211_STA_AP_CLIENT: client of an AP interface
@@ -2132,7 +2148,7 @@ struct cfg80211_qos_map {
  * @stop_ap: Stop being an AP, including stopping beaconing.
  *
  * @add_station: Add a new station.
- * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ * @del_station: Remove a station
  * @change_station: Modify a given station. Note that flags changes are not much
  *     validated in cfg80211, in particular the auth/assoc/authorized flags
  *     might come to the driver in invalid combinations -- make sure to check
@@ -2146,6 +2162,8 @@ struct cfg80211_qos_map {
  * @change_mpath: change a given mesh path
  * @get_mpath: get a mesh path for the given parameters
  * @dump_mpath: dump mesh path callback -- resume dump at index @idx
+ * @get_mpp: get a mesh proxy path for the given parameters
+ * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx
  * @join_mesh: join the mesh network with the specified parameters
  *     (invoked with the wireless_dev mutex held)
  * @leave_mesh: leave the current mesh network
@@ -2376,7 +2394,7 @@ struct cfg80211_ops {
                               const u8 *mac,
                               struct station_parameters *params);
        int     (*del_station)(struct wiphy *wiphy, struct net_device *dev,
-                              const u8 *mac);
+                              struct station_del_parameters *params);
        int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
                                  const u8 *mac,
                                  struct station_parameters *params);
@@ -2396,6 +2414,11 @@ struct cfg80211_ops {
        int     (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
                              int idx, u8 *dst, u8 *next_hop,
                              struct mpath_info *pinfo);
+       int     (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
+                          u8 *dst, u8 *mpp, struct mpath_info *pinfo);
+       int     (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
+                           int idx, u8 *dst, u8 *mpp,
+                           struct mpath_info *pinfo);
        int     (*get_mesh_config)(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct mesh_config *conf);
index 0ad1f47..9bb2fc7 100644 (file)
@@ -1117,6 +1117,8 @@ struct ieee80211_conf {
  *     Function (TSF) timer when the frame containing the channel switch
  *     announcement was received. This is simply the rx.mactime parameter
  *     the driver passed into mac80211.
+ * @device_timestamp: arbitrary timestamp for the device, this is the
+ *     rx.device_timestamp parameter the driver passed to mac80211.
  * @block_tx: Indicates whether transmission must be blocked before the
  *     scheduled channel switch, as indicated by the AP.
  * @chandef: the new channel to switch to
@@ -1124,6 +1126,7 @@ struct ieee80211_conf {
  */
 struct ieee80211_channel_switch {
        u64 timestamp;
+       u32 device_timestamp;
        bool block_tx;
        struct cfg80211_chan_def chandef;
        u8 count;
@@ -2829,6 +2832,13 @@ enum ieee80211_roc_type {
  *     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.
+ * @pre_channel_switch: This is an optional callback that is called
+ *     before a channel switch procedure is started (ie. when a STA
+ *     gets a CSA or an userspace initiated channel-switch), allowing
+ *     the driver to prepare for the channel switch.
+ * @post_channel_switch: This is an optional callback that is called
+ *     after a channel switch procedure is completed, allowing the
+ *     driver to go back to a normal configuration.
  *
  * @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
@@ -2959,6 +2969,7 @@ struct ieee80211_ops {
        void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                      u32 queues, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
                               struct ieee80211_channel_switch *ch_switch);
        int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
        int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
@@ -3035,6 +3046,12 @@ struct ieee80211_ops {
        void (*channel_switch_beacon)(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      struct cfg80211_chan_def *chandef);
+       int (*pre_channel_switch)(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_channel_switch *ch_switch);
+
+       int (*post_channel_switch)(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif);
 
        int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
index 4b28dc0..b553c48 100644 (file)
  *     the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
  *     or, if no MAC address given, all stations, on the interface identified
- *     by %NL80211_ATTR_IFINDEX.
+ *     by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ *     %NL80211_ATTR_REASON_CODE can optionally be used to specify which type
+ *     of disconnection indication should be sent to the station
+ *     (Deauthentication or Disassociation frame and reason code for that
+ *     frame).
  *
  * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
  *     destination %NL80211_ATTR_MAC on the interface identified by
  *     before removing a station entry entirely, or before disassociating
  *     or similar, cleanup will happen in the driver/device in this case.
  *
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ *     destination %NL80211_ATTR_MAC on the interface identified by
+ *     %NL80211_ATTR_IFINDEX.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -912,6 +920,8 @@ enum nl80211_commands {
        NL80211_CMD_ADD_TX_TS,
        NL80211_CMD_DEL_TX_TS,
 
+       NL80211_CMD_GET_MPP,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
index 343da1e..64deb9a 100644 (file)
@@ -1225,14 +1225,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                                const u8 *mac)
+                                struct station_del_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (mac)
-               return sta_info_destroy_addr_bss(sdata, mac);
+       if (params->mac)
+               return sta_info_destroy_addr_bss(sdata, params->mac);
 
        sta_info_flush(sdata);
        return 0;
@@ -1516,6 +1516,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
+                         struct mpath_info *pinfo)
+{
+       memset(pinfo, 0, sizeof(*pinfo));
+       memcpy(mpp, mpath->mpp, ETH_ALEN);
+
+       pinfo->generation = mpp_paths_generation;
+}
+
+static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
+                            u8 *dst, u8 *mpp, struct mpath_info *pinfo)
+
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup(sdata, dst);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
+                             int idx, u8 *dst, u8 *mpp,
+                             struct mpath_info *pinfo)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup_by_idx(sdata, idx);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
 static int ieee80211_get_mesh_config(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct mesh_config *conf)
@@ -2850,11 +2901,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                if (sdata->reserved_ready)
                        return 0;
 
-               err = ieee80211_vif_use_reserved_context(sdata);
-               if (err)
-                       return err;
-
-               return 0;
+               return ieee80211_vif_use_reserved_context(sdata);
        }
 
        if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
@@ -2868,7 +2915,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                return err;
 
        ieee80211_bss_info_change_notify(sdata, changed);
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
@@ -2876,6 +2922,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                sdata->csa_block_tx = false;
        }
 
+       err = drv_post_channel_switch(sdata);
+       if (err)
+               return err;
+
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
        return 0;
 }
 
@@ -3053,9 +3105,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel_switch ch_switch;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *chanctx;
-       int err, changed = 0;
+       u32 changed = 0;
+       int err;
 
        sdata_assert_lock(sdata);
        lockdep_assert_held(&local->mtx);
@@ -3088,6 +3142,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       err = drv_pre_channel_switch(sdata, &ch_switch);
+       if (err)
+               goto out;
+
        err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
                                            chanctx->mode,
                                            params->radar_required);
@@ -3101,6 +3159,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       ch_switch.timestamp = 0;
+       ch_switch.device_timestamp = 0;
+       ch_switch.block_tx = params->block_tx;
+       ch_switch.chandef = params->chandef;
+       ch_switch.count = params->count;
+
        err = ieee80211_set_csa_beacon(sdata, params, &changed);
        if (err) {
                ieee80211_vif_unreserve_chanctx(sdata);
@@ -3547,6 +3611,8 @@ const struct cfg80211_ops mac80211_config_ops = {
        .change_mpath = ieee80211_change_mpath,
        .get_mpath = ieee80211_get_mpath,
        .dump_mpath = ieee80211_dump_mpath,
+       .get_mpp = ieee80211_get_mpp,
+       .dump_mpp = ieee80211_dump_mpp,
        .update_mesh_config = ieee80211_update_mesh_config,
        .get_mesh_config = ieee80211_get_mesh_config,
        .join_mesh = ieee80211_join_mesh,
index 196d48c..1bbb079 100644 (file)
@@ -764,12 +764,13 @@ static inline void drv_flush(struct ieee80211_local *local,
 }
 
 static inline void drv_channel_switch(struct ieee80211_local *local,
-                                    struct ieee80211_channel_switch *ch_switch)
+                                     struct ieee80211_sub_if_data *sdata,
+                                     struct ieee80211_channel_switch *ch_switch)
 {
        might_sleep();
 
-       trace_drv_channel_switch(local, ch_switch);
-       local->ops->channel_switch(&local->hw, ch_switch);
+       trace_drv_channel_switch(local, sdata, ch_switch);
+       local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch);
        trace_drv_return_void(local);
 }
 
@@ -1196,6 +1197,40 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
        }
 }
 
+static inline int
+drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_channel_switch *ch_switch)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret = 0;
+
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       trace_drv_pre_channel_switch(local, sdata, ch_switch);
+       if (local->ops->pre_channel_switch)
+               ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif,
+                                                    ch_switch);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+static inline int
+drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret = 0;
+
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       trace_drv_post_channel_switch(local, sdata);
+       if (local->ops->post_channel_switch)
+               ret = local->ops->post_channel_switch(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
 static inline int drv_join_ibss(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata)
 {
index c2aaec4..78d6121 100644 (file)
@@ -434,6 +434,8 @@ struct ieee80211_if_managed {
 
        unsigned int flags;
 
+       bool csa_waiting_bcn;
+
        bool beacon_crc_valid;
        u32 beacon_crc;
 
@@ -1307,6 +1309,9 @@ struct ieee80211_local {
        /* virtual monitor interface */
        struct ieee80211_sub_if_data __rcu *monitor_sdata;
        struct cfg80211_chan_def monitor_chandef;
+
+       /* extended capabilities provided by mac80211 */
+       u8 ext_capa[8];
 };
 
 static inline struct ieee80211_sub_if_data *
index af23722..e469b33 100644 (file)
@@ -842,6 +842,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        sdata_lock(sdata);
        mutex_lock(&local->mtx);
        sdata->vif.csa_active = false;
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               sdata->u.mgd.csa_waiting_bcn = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
index 0de7c93..9e322dc 100644 (file)
@@ -478,11 +478,6 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
        },
 };
 
-static const u8 extended_capabilities[] = {
-       0, 0, 0, 0, 0, 0, 0,
-       WLAN_EXT_CAPA8_OPMODE_NOTIF,
-};
-
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
@@ -539,10 +534,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                        WIPHY_FLAG_REPORTS_OBSS |
                        WIPHY_FLAG_OFFCHAN_TX;
 
-       wiphy->extended_capabilities = extended_capabilities;
-       wiphy->extended_capabilities_mask = extended_capabilities;
-       wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities);
-
        if (ops->remain_on_channel)
                wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
@@ -591,6 +582,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
        wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
 
+       local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF;
+
+       wiphy->extended_capabilities = local->ext_capa;
+       wiphy->extended_capabilities_mask = local->ext_capa;
+       wiphy->extended_capabilities_len =
+               ARRAY_SIZE(local->ext_capa);
+
        INIT_LIST_HEAD(&local->interfaces);
 
        __hw_addr_init(&local->mc_list);
@@ -787,13 +785,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
                        return -EINVAL;
 
-               /* DFS currently not supported with channel context drivers */
+               /* DFS is not supported with multi-channel combinations yet */
                for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
                        const struct ieee80211_iface_combination *comb;
 
                        comb = &local->hw.wiphy->iface_combinations[i];
 
-                       if (comb->radar_detect_widths)
+                       if (comb->radar_detect_widths &&
+                           comb->num_different_channels > 1)
                                return -EINVAL;
                }
        }
@@ -958,6 +957,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
                local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
 
+       /* mac80211 supports eCSA, if the driver supports STA CSA at all */
+       if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)
+               local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
+
        local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
 
        result = wiphy_register(local->hw.wiphy);
index f39a19f..50c8473 100644 (file)
@@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
                 const u8 *dst, const u8 *mpp);
 struct mesh_path *
 mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
 void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
 void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
 void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
@@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
 
 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
 extern int mesh_paths_generation;
+extern int mpp_paths_generation;
 
 #ifdef CONFIG_MAC80211_MESH
 static inline
index a6699dc..b890e22 100644 (file)
@@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths;
 static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
 
 int mesh_paths_generation;
+int mpp_paths_generation;
 
 /* This lock will have the grow table function as writer and add / delete nodes
  * as readers. RCU provides sufficient protection only when reading the table
@@ -409,6 +410,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
        return NULL;
 }
 
+/**
+ * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
+ * @idx: index
+ * @sdata: local subif, or NULL for all entries
+ *
+ * Returns: pointer to the proxy path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
+{
+       struct mesh_table *tbl = rcu_dereference(mpp_paths);
+       struct mpath_node *node;
+       int i;
+       int j = 0;
+
+       for_each_mesh_entry(tbl, node, i) {
+               if (sdata && node->mpath->sdata != sdata)
+                       continue;
+               if (j++ == idx)
+                       return node->mpath;
+       }
+
+       return NULL;
+}
+
 /**
  * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
  * @mpath: gate path to add to table
@@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
 
        spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
+
+       mpp_paths_generation++;
+
        if (grow) {
                set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
                ieee80211_queue_work(&local->hw, &sdata->work);
index 2de8870..fb65615 100644 (file)
@@ -1001,14 +1001,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        /* XXX: shouldn't really modify cfg80211-owned data! */
        ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-       sdata->vif.csa_active = false;
-
-       /* XXX: wait for a beacon first? */
-       if (sdata->csa_block_tx) {
-               ieee80211_wake_vif_queues(local, sdata,
-                                         IEEE80211_QUEUE_STOP_REASON_CSA);
-               sdata->csa_block_tx = false;
-       }
+       ifmgd->csa_waiting_bcn = true;
 
        ieee80211_sta_reset_beacon_monitor(sdata);
        ieee80211_sta_reset_conn_monitor(sdata);
@@ -1019,6 +1012,35 @@ out:
        sdata_unlock(sdata);
 }
 
+static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       int ret;
+
+       sdata_assert_lock(sdata);
+
+       WARN_ON(!sdata->vif.csa_active);
+
+       if (sdata->csa_block_tx) {
+               ieee80211_wake_vif_queues(local, sdata,
+                                         IEEE80211_QUEUE_STOP_REASON_CSA);
+               sdata->csa_block_tx = false;
+       }
+
+       sdata->vif.csa_active = false;
+       ifmgd->csa_waiting_bcn = false;
+
+       ret = drv_post_channel_switch(sdata);
+       if (ret) {
+               sdata_info(sdata,
+                          "driver post channel switch failed, disconnecting\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               return;
+       }
+}
+
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -1046,7 +1068,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 static void
 ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-                                u64 timestamp, struct ieee802_11_elems *elems,
+                                u64 timestamp, u32 device_timestamp,
+                                struct ieee802_11_elems *elems,
                                 bool beacon)
 {
        struct ieee80211_local *local = sdata->local;
@@ -1056,6 +1079,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_chanctx *chanctx;
        enum ieee80211_band current_band;
        struct ieee80211_csa_ie csa_ie;
+       struct ieee80211_channel_switch ch_switch;
        int res;
 
        sdata_assert_lock(sdata);
@@ -1110,21 +1134,31 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       if (local->use_chanctx) {
-               u32 num_chanctx = 0;
-               list_for_each_entry(chanctx, &local->chanctx_list, list)
-                      num_chanctx++;
+       if (local->use_chanctx &&
+           !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+               sdata_info(sdata,
+                          "driver doesn't support chan-switch with channel contexts\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               mutex_unlock(&local->chanctx_mtx);
+               mutex_unlock(&local->mtx);
+               return;
+       }
 
-               if (num_chanctx > 1 ||
-                   !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
-                       sdata_info(sdata,
-                                  "not handling chan-switch with channel contexts\n");
-                       ieee80211_queue_work(&local->hw,
-                                            &ifmgd->csa_connection_drop_work);
-                       mutex_unlock(&local->chanctx_mtx);
-                       mutex_unlock(&local->mtx);
-                       return;
-               }
+       ch_switch.timestamp = timestamp;
+       ch_switch.device_timestamp = device_timestamp;
+       ch_switch.block_tx = csa_ie.mode;
+       ch_switch.chandef = csa_ie.chandef;
+       ch_switch.count = csa_ie.count;
+
+       if (drv_pre_channel_switch(sdata, &ch_switch)) {
+               sdata_info(sdata,
+                          "preparing for channel switch failed, disconnecting\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               mutex_unlock(&local->chanctx_mtx);
+               mutex_unlock(&local->mtx);
+               return;
        }
 
        res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
@@ -1152,14 +1186,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        if (local->ops->channel_switch) {
                /* use driver's channel switch callback */
-               struct ieee80211_channel_switch ch_switch = {
-                       .timestamp = timestamp,
-                       .block_tx = csa_ie.mode,
-                       .chandef = csa_ie.chandef,
-                       .count = csa_ie.count,
-               };
-
-               drv_channel_switch(local, &ch_switch);
+               drv_channel_switch(local, sdata, &ch_switch);
                return;
        }
 
@@ -1923,6 +1950,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        ieee80211_vif_release_channel(sdata);
 
        sdata->vif.csa_active = false;
+       ifmgd->csa_waiting_bcn = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -2171,6 +2199,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
                               true, frame_buf);
        mutex_lock(&local->mtx);
        sdata->vif.csa_active = false;
+       ifmgd->csa_waiting_bcn = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3195,6 +3224,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       if (ifmgd->csa_waiting_bcn)
+               ieee80211_chswitch_post_beacon(sdata);
+
        if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
                return;
        ifmgd->beacon_crc = ncrc;
@@ -3203,6 +3235,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 
        ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+                                        rx_status->device_timestamp,
                                         &elems, true);
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
@@ -3334,8 +3367,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                break;
 
                        ieee80211_sta_process_chanswitch(sdata,
-                                                        rx_status->mactime,
-                                                        &elems, false);
+                                                rx_status->mactime,
+                                                rx_status->device_timestamp,
+                                                &elems, false);
                } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
                        ies_len = skb->len -
                                  offsetof(struct ieee80211_mgmt,
@@ -3356,8 +3390,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                &mgmt->u.action.u.ext_chan_switch.data;
 
                        ieee80211_sta_process_chanswitch(sdata,
-                                                        rx_status->mactime,
-                                                        &elems, false);
+                                                rx_status->mactime,
+                                                rx_status->device_timestamp,
+                                                &elems, false);
                }
                break;
        }
@@ -3664,11 +3699,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        if (local->quiescing)
                return;
 
-       if (sdata->vif.csa_active)
+       if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
                return;
 
        sdata->u.mgd.connection_loss = false;
@@ -3686,7 +3722,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
        if (local->quiescing)
                return;
 
-       if (sdata->vif.csa_active)
+       if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
                return;
 
        ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
index df90ce2..17ef54a 100644 (file)
@@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
 static int
 minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
 {
-       return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
+       return GROUP_IDX((rate->idx / 8) + 1,
                         !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
                         !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
 }
index 38fae7e..976606a 100644 (file)
@@ -987,29 +987,34 @@ TRACE_EVENT(drv_flush,
 
 TRACE_EVENT(drv_channel_switch,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_channel_switch *ch_switch),
 
-       TP_ARGS(local, ch_switch),
+       TP_ARGS(local, sdata, ch_switch),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                CHANDEF_ENTRY
                __field(u64, timestamp)
+               __field(u32, device_timestamp)
                __field(bool, block_tx)
                __field(u8, count)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                CHANDEF_ASSIGN(&ch_switch->chandef)
                __entry->timestamp = ch_switch->timestamp;
+               __entry->device_timestamp = ch_switch->device_timestamp;
                __entry->block_tx = ch_switch->block_tx;
                __entry->count = ch_switch->count;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
-               LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
+               LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count
        )
 );
 
@@ -2106,6 +2111,45 @@ TRACE_EVENT(drv_channel_switch_beacon,
        )
 );
 
+TRACE_EVENT(drv_pre_channel_switch,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_channel_switch *ch_switch),
+
+       TP_ARGS(local, sdata, ch_switch),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               CHANDEF_ENTRY
+               __field(u64, timestamp)
+               __field(bool, block_tx)
+               __field(u8, count)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               CHANDEF_ASSIGN(&ch_switch->chandef)
+               __entry->timestamp = ch_switch->timestamp;
+               __entry->block_tx = ch_switch->block_tx;
+               __entry->count = ch_switch->count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to "
+               CHANDEF_PR_FMT  " count:%d block_tx:%d timestamp:%llu",
+               LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count,
+               __entry->block_tx, __entry->timestamp
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch,
+            TP_PROTO(struct ieee80211_local *local,
+                     struct ieee80211_sub_if_data *sdata),
+            TP_ARGS(local, sdata)
+);
+
 
 #ifdef CONFIG_MAC80211_MESSAGE_TRACING
 #undef TRACE_SYSTEM
index 3c61060..c76c9d7 100644 (file)
@@ -2526,11 +2526,23 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, radar_detected_work);
        struct cfg80211_chan_def chandef = local->hw.conf.chandef;
+       struct ieee80211_chanctx *ctx;
+       int num_chanctx = 0;
+
+       mutex_lock(&local->chanctx_mtx);
+       list_for_each_entry(ctx, &local->chanctx_list, list) {
+               if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
+                       continue;
+
+               num_chanctx++;
+               chandef = ctx->conf.def;
+       }
+       mutex_unlock(&local->chanctx_mtx);
 
        ieee80211_dfs_cac_cancel(local);
 
-       if (local->use_chanctx)
-               /* currently not handled */
+       if (num_chanctx > 1)
+               /* XXX: multi-channel is not supported yet */
                WARN_ON(1);
        else
                cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
index 5839c85..d05fe6d 100644 (file)
@@ -4398,10 +4398,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
-       u8 *mac_addr = NULL;
+       struct station_del_parameters params;
+
+       memset(&params, 0, sizeof(params));
 
        if (info->attrs[NL80211_ATTR_MAC])
-               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+               params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
@@ -4412,7 +4414,28 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->del_station)
                return -EOPNOTSUPP;
 
-       return rdev_del_station(rdev, dev, mac_addr);
+       if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
+               params.subtype =
+                       nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
+               if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
+                   params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
+                       return -EINVAL;
+       } else {
+               /* Default to Deauthentication frame */
+               params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
+       }
+
+       if (info->attrs[NL80211_ATTR_REASON_CODE]) {
+               params.reason_code =
+                       nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+               if (params.reason_code == 0)
+                       return -EINVAL; /* 0 is reserved */
+       } else {
+               /* Default to reason code 2 */
+               params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
+       }
+
+       return rdev_del_station(rdev, dev, &params);
 }
 
 static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
@@ -4624,6 +4647,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
        return rdev_del_mpath(rdev, dev, dst);
 }
 
+static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       int err;
+       struct net_device *dev = info->user_ptr[1];
+       struct mpath_info pinfo;
+       struct sk_buff *msg;
+       u8 *dst = NULL;
+       u8 mpp[ETH_ALEN];
+
+       memset(&pinfo, 0, sizeof(pinfo));
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       if (!rdev->ops->get_mpp)
+               return -EOPNOTSUPP;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
+
+       err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
+       if (err)
+               return err;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
+                              dev, dst, mpp, &pinfo) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int nl80211_dump_mpp(struct sk_buff *skb,
+                           struct netlink_callback *cb)
+{
+       struct mpath_info pinfo;
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       u8 dst[ETH_ALEN];
+       u8 mpp[ETH_ALEN];
+       int path_idx = cb->args[2];
+       int err;
+
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+       if (err)
+               return err;
+
+       if (!rdev->ops->dump_mpp) {
+               err = -EOPNOTSUPP;
+               goto out_err;
+       }
+
+       if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
+               err = -EOPNOTSUPP;
+               goto out_err;
+       }
+
+       while (1) {
+               err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
+                                   mpp, &pinfo);
+               if (err == -ENOENT)
+                       break;
+               if (err)
+                       goto out_err;
+
+               if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
+                                      cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                      wdev->netdev, dst, mpp,
+                                      &pinfo) < 0)
+                       goto out;
+
+               path_idx++;
+       }
+
+ out:
+       cb->args[2] = path_idx;
+       err = skb->len;
+ out_err:
+       nl80211_finish_wdev_dump(rdev);
+       return err;
+}
+
 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -9781,6 +9894,15 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_GET_MPP,
+               .doit = nl80211_get_mpp,
+               .dumpit = nl80211_dump_mpp,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
        {
                .cmd = NL80211_CMD_SET_MPATH,
                .doit = nl80211_set_mpath,
index f6d457d..71b1db3 100644 (file)
@@ -178,11 +178,12 @@ static inline int rdev_add_station(struct cfg80211_registered_device *rdev,
 }
 
 static inline int rdev_del_station(struct cfg80211_registered_device *rdev,
-                                  struct net_device *dev, u8 *mac)
+                                  struct net_device *dev,
+                                  struct station_del_parameters *params)
 {
        int ret;
-       trace_rdev_del_station(&rdev->wiphy, dev, mac);
-       ret = rdev->ops->del_station(&rdev->wiphy, dev, mac);
+       trace_rdev_del_station(&rdev->wiphy, dev, params);
+       ret = rdev->ops->del_station(&rdev->wiphy, dev, params);
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
@@ -263,6 +264,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
 
 }
 
+static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev,
+                              struct net_device *dev, u8 *dst, u8 *mpp,
+                              struct mpath_info *pinfo)
+{
+       int ret;
+
+       trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp);
+       ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo);
+       trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+       return ret;
+}
+
 static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
                                  struct net_device *dev, int idx, u8 *dst,
                                  u8 *next_hop, struct mpath_info *pinfo)
@@ -271,7 +284,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
        int ret;
        trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
        ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
-                                    pinfo);
+                                   pinfo);
+       trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+       return ret;
+}
+
+static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev,
+                               struct net_device *dev, int idx, u8 *dst,
+                               u8 *mpp, struct mpath_info *pinfo)
+
+{
+       int ret;
+
+       trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp);
+       ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo);
        trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
        return ret;
 }
index dc1668f..0ab3711 100644 (file)
@@ -80,9 +80,18 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
        if (!request)
                return -ENOMEM;
 
-       if (wdev->conn->params.channel)
+       if (wdev->conn->params.channel) {
+               enum ieee80211_band band = wdev->conn->params.channel->band;
+               struct ieee80211_supported_band *sband =
+                       wdev->wiphy->bands[band];
+
+               if (!sband) {
+                       kfree(request);
+                       return -EINVAL;
+               }
                request->channels[0] = wdev->conn->params.channel;
-       else {
+               request->rates[band] = (1 << sband->n_bitrates) - 1;
+       } else {
                int i = 0, j;
                enum ieee80211_band band;
                struct ieee80211_supported_band *bands;
index 625a6e6..cdb2c2e 100644 (file)
@@ -680,9 +680,34 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac))
 );
 
-DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station,
-       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
-       TP_ARGS(wiphy, netdev, mac)
+DECLARE_EVENT_CLASS(station_del,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct station_del_parameters *params),
+       TP_ARGS(wiphy, netdev, params),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(sta_mac)
+               __field(u8, subtype)
+               __field(u16, reason_code)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(sta_mac, params->mac);
+               __entry->subtype = params->subtype;
+               __entry->reason_code = params->reason_code;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+                 ", subtype: %u, reason_code: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
+                 __entry->subtype, __entry->reason_code)
+);
+
+DEFINE_EVENT(station_del, rdev_del_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct station_del_parameters *params),
+       TP_ARGS(wiphy, netdev, params)
 );
 
 DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station,
@@ -801,6 +826,51 @@ TRACE_EVENT(rdev_dump_mpath,
                  MAC_PR_ARG(next_hop))
 );
 
+TRACE_EVENT(rdev_get_mpp,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                u8 *dst, u8 *mpp),
+       TP_ARGS(wiphy, netdev, dst, mpp),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(dst)
+               MAC_ENTRY(mpp)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(dst, dst);
+               MAC_ASSIGN(mpp, mpp);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT
+                 ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG,
+                 MAC_PR_ARG(dst), MAC_PR_ARG(mpp))
+);
+
+TRACE_EVENT(rdev_dump_mpp,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
+                u8 *dst, u8 *mpp),
+       TP_ARGS(wiphy, netdev, idx, mpp, dst),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(dst)
+               MAC_ENTRY(mpp)
+               __field(int, idx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(dst, dst);
+               MAC_ASSIGN(mpp, mpp);
+               __entry->idx = idx;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
+                 MAC_PR_FMT ", mpp: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
+                 MAC_PR_ARG(mpp))
+);
+
 TRACE_EVENT(rdev_return_int_mpath_info,
        TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
        TP_ARGS(wiphy, ret, pinfo),