]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/net/wireless/mac80211_hwsim.c
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
[mirror_ubuntu-bionic-kernel.git] / drivers / net / wireless / mac80211_hwsim.c
index 69d4c3179d042159122911539f41619ae7e71597..9d7a52f5a4102abedd2dbebc03c26c3866da2a64 100644 (file)
@@ -57,6 +57,10 @@ static bool rctbl = false;
 module_param(rctbl, bool, 0444);
 MODULE_PARM_DESC(rctbl, "Handle rate control table");
 
+static bool support_p2p_device = true;
+module_param(support_p2p_device, bool, 0444);
+MODULE_PARM_DESC(support_p2p_device, "Support P2P-Device interface type");
+
 /**
  * enum hwsim_regtest - the type of regulatory tests we offer
  *
@@ -335,7 +339,8 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
 #endif
                                 BIT(NL80211_IFTYPE_AP) |
                                 BIT(NL80211_IFTYPE_P2P_GO) },
-       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
+       /* must be last, see hwsim_if_comb */
+       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }
 };
 
 static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
@@ -343,6 +348,27 @@ static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
 };
 
 static const struct ieee80211_iface_combination hwsim_if_comb[] = {
+       {
+               .limits = hwsim_if_limits,
+               /* remove the last entry which is P2P_DEVICE */
+               .n_limits = ARRAY_SIZE(hwsim_if_limits) - 1,
+               .max_interfaces = 2048,
+               .num_different_channels = 1,
+       },
+       {
+               .limits = hwsim_if_dfs_limits,
+               .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
+               .max_interfaces = 8,
+               .num_different_channels = 1,
+               .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                      BIT(NL80211_CHAN_WIDTH_20) |
+                                      BIT(NL80211_CHAN_WIDTH_40) |
+                                      BIT(NL80211_CHAN_WIDTH_80) |
+                                      BIT(NL80211_CHAN_WIDTH_160),
+       }
+};
+
+static const struct ieee80211_iface_combination hwsim_if_comb_p2p_dev[] = {
        {
                .limits = hwsim_if_limits,
                .n_limits = ARRAY_SIZE(hwsim_if_limits),
@@ -385,6 +411,7 @@ struct mac80211_hwsim_data {
 
        struct mac_address addresses[2];
        int channels, idx;
+       bool use_chanctx;
 
        struct ieee80211_channel *tmp_chan;
        struct delayed_work roc_done;
@@ -451,7 +478,7 @@ static struct genl_family hwsim_genl_family = {
 
 /* MAC80211_HWSIM netlink policy */
 
-static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
+static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
        [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, .len = ETH_ALEN },
        [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY,
@@ -468,6 +495,7 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_REG_HINT_ALPHA2] = { .type = NLA_STRING, .len = 2 },
        [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
        [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
+       [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1035,32 +1063,6 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
                        ack = true;
 
                rx_status.mactime = now + data2->tsf_offset;
-#if 0
-               /*
-                * Don't enable this code by default as the OUI 00:00:00
-                * is registered to Xerox so we shouldn't use it here, it
-                * might find its way into pcap files.
-                * Note that this code requires the headroom in the SKB
-                * that was allocated earlier.
-                */
-               rx_status.vendor_radiotap_oui[0] = 0x00;
-               rx_status.vendor_radiotap_oui[1] = 0x00;
-               rx_status.vendor_radiotap_oui[2] = 0x00;
-               rx_status.vendor_radiotap_subns = 127;
-               /*
-                * Radiotap vendor namespaces can (and should) also be
-                * split into fields by using the standard radiotap
-                * presence bitmap mechanism. Use just BIT(0) here for
-                * the presence bitmap.
-                */
-               rx_status.vendor_radiotap_bitmap = BIT(0);
-               /* We have 8 bytes of (dummy) data */
-               rx_status.vendor_radiotap_len = 8;
-               /* For testing, also require it to be aligned */
-               rx_status.vendor_radiotap_align = 8;
-               /* push the data */
-               memcpy(skb_push(nskb, 8), "ABCDEFGH", 8);
-#endif
 
                memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
                ieee80211_rx_irqsafe(data2->hw, nskb);
@@ -1087,7 +1089,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
                return;
        }
 
-       if (data->channels == 1) {
+       if (!data->use_chanctx) {
                channel = data->channel;
        } else if (txi->hw_queue == 4) {
                channel = data->tmp_chan;
@@ -1275,6 +1277,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
 
        mac80211_hwsim_tx_frame(hw, skb,
                                rcu_dereference(vif->chanctx_conf)->def.chan);
+
+       if (vif->csa_active && ieee80211_csa_is_complete(vif))
+               ieee80211_csa_finish(vif);
 }
 
 static enum hrtimer_restart
@@ -1350,7 +1355,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 
        data->channel = conf->chandef.chan;
 
-       WARN_ON(data->channel && data->channels > 1);
+       WARN_ON(data->channel && data->use_chanctx);
 
        data->power_level = conf->power_level;
        if (!data->started || !data->beacon_int)
@@ -1936,7 +1941,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 reg_strict, bool p2p_device,
+                                      bool use_chanctx)
 {
        int err;
        u8 addr[ETH_ALEN];
@@ -1946,11 +1952,14 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
        int idx;
 
+       if (WARN_ON(channels > 1 && !use_chanctx))
+               return -EINVAL;
+
        spin_lock_bh(&hwsim_radio_lock);
        idx = hwsim_radio_idx++;
        spin_unlock_bh(&hwsim_radio_lock);
 
-       if (channels > 1)
+       if (use_chanctx)
                ops = &mac80211_hwsim_mchan_ops;
        hw = ieee80211_alloc_hw(sizeof(*data), ops);
        if (!hw) {
@@ -1991,17 +2000,25 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        hw->wiphy->addresses = data->addresses;
 
        data->channels = channels;
+       data->use_chanctx = use_chanctx;
        data->idx = idx;
 
-       if (data->channels > 1) {
+       if (data->use_chanctx) {
                hw->wiphy->max_scan_ssids = 255;
                hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
                hw->wiphy->max_remain_on_channel_duration = 1000;
                /* For channels > 1 DFS is not allowed */
                hw->wiphy->n_iface_combinations = 1;
                hw->wiphy->iface_combinations = &data->if_combination;
-               data->if_combination = hwsim_if_comb[0];
+               if (p2p_device)
+                       data->if_combination = hwsim_if_comb_p2p_dev[0];
+               else
+                       data->if_combination = hwsim_if_comb[0];
                data->if_combination.num_different_channels = data->channels;
+       } else if (p2p_device) {
+               hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(hwsim_if_comb_p2p_dev);
        } else {
                hw->wiphy->iface_combinations = hwsim_if_comb;
                hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
@@ -2017,8 +2034,10 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                                     BIT(NL80211_IFTYPE_P2P_CLIENT) |
                                     BIT(NL80211_IFTYPE_P2P_GO) |
                                     BIT(NL80211_IFTYPE_ADHOC) |
-                                    BIT(NL80211_IFTYPE_MESH_POINT) |
-                                    BIT(NL80211_IFTYPE_P2P_DEVICE);
+                                    BIT(NL80211_IFTYPE_MESH_POINT);
+
+       if (p2p_device)
+               hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
 
        hw->flags = IEEE80211_HW_MFP_CAPABLE |
                    IEEE80211_HW_SIGNAL_DBM |
@@ -2027,13 +2046,15 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_WANT_MONITOR_VIF |
                    IEEE80211_HW_QUEUE_CONTROL |
-                   IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
+                   IEEE80211_HW_SUPPORTS_HT_CCK_RATES |
+                   IEEE80211_HW_CHANCTX_STA_CSA;
        if (rctbl)
                hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
 
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
                            WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
-                           WIPHY_FLAG_AP_UAPSD;
+                           WIPHY_FLAG_AP_UAPSD |
+                           WIPHY_FLAG_HAS_CHANNEL_SWITCH;
        hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
 
        /* ask mac80211 to reserve space for magic */
@@ -2141,7 +2162,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
        debugfs_create_file("group", 0666, data->debugfs, data,
                            &hwsim_fops_group);
-       if (data->channels == 1)
+       if (!data->use_chanctx)
                debugfs_create_file("dfs_simulate_radar", 0222,
                                    data->debugfs,
                                    data, &hwsim_simulate_radar);
@@ -2407,10 +2428,17 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
        const char *alpha2 = NULL;
        const struct ieee80211_regdomain *regd = NULL;
        bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
+       bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+       bool use_chanctx;
 
        if (info->attrs[HWSIM_ATTR_CHANNELS])
                chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
 
+       if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
+               use_chanctx = true;
+       else
+               use_chanctx = (chans > 1);
+
        if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
                alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
 
@@ -2422,7 +2450,8 @@ static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
                regd = hwsim_world_regdom_custom[idx];
        }
 
-       return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict);
+       return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
+                                          p2p_device, use_chanctx);
 }
 
 static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
@@ -2640,7 +2669,9 @@ static int __init init_mac80211_hwsim(void)
                }
 
                err = mac80211_hwsim_create_radio(channels, reg_alpha2,
-                                                 regd, reg_strict);
+                                                 regd, reg_strict,
+                                                 support_p2p_device,
+                                                 channels > 1);
                if (err < 0)
                        goto out_free_radios;
        }