From 8fe02e167efa8ed4a4503a5eedc0f49fcb7e3eb9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:22:25 +0200 Subject: cfg80211: consolidate passive-scan and no-ibss flags These two flags are used for the same purpose, just combine them into a no-ir flag to annotate no initiating radiation is allowed. Old userspace sending either flag will have it treated as the no-ir flag. To be considerate to older userspace we also send both the no-ir flag and the old no-ibss flags. Newer userspace will have to be aware of older kernels. Update all places in the tree using these flags with the following semantic patch: @@ @@ -NL80211_RRF_PASSIVE_SCAN +NL80211_RRF_NO_IR @@ @@ -NL80211_RRF_NO_IBSS +NL80211_RRF_NO_IR @@ @@ -IEEE80211_CHAN_PASSIVE_SCAN +IEEE80211_CHAN_NO_IR @@ @@ -IEEE80211_CHAN_NO_IBSS +IEEE80211_CHAN_NO_IR @@ @@ -NL80211_RRF_NO_IR | NL80211_RRF_NO_IR +NL80211_RRF_NO_IR @@ @@ -IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_IR +IEEE80211_CHAN_NO_IR @@ @@ -(NL80211_RRF_NO_IR) +NL80211_RRF_NO_IR @@ @@ -(IEEE80211_CHAN_NO_IR) +IEEE80211_CHAN_NO_IR Along with some hand-optimisations in documentation, to remove duplicates and to fix some indentation. Signed-off-by: Luis R. Rodriguez [do all the driver updates in one go] Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index de0df86704e7..33d4b31995da 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { .reg_rules = { REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), REG_RULE(5725-10, 5850+10, 40, 0, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), } }; @@ -1485,7 +1485,7 @@ static void hw_scan_work(struct work_struct *work) req->channels[hwsim->scan_chan_idx]->center_freq); hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; - if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR || !req->n_ssids) { dwell = 120; } else { -- cgit v1.2.3 From 70526e543c8087b7fa136fd5e6be98332d609848 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Fri, 1 Nov 2013 20:35:58 +0100 Subject: mac80211_hwsim: use debugfs_remove_recursive Use debugfs_remove_recursive. That avoids the need for the new dentry pointers and extra debugfs_remove calls. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 33d4b31995da..76b362ed76bd 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -353,7 +353,6 @@ struct mac80211_hwsim_data { } ps; bool ps_poll_pending; struct dentry *debugfs; - struct dentry *debugfs_ps; struct sk_buff_head pending; /* packets pending */ /* @@ -362,7 +361,6 @@ struct mac80211_hwsim_data { * radio can be in more then one group. */ u64 group; - struct dentry *debugfs_group; int power_level; @@ -1734,9 +1732,7 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry_safe(data, tmpdata, &tmplist, list) { - debugfs_remove(data->debugfs_group); - debugfs_remove(data->debugfs_ps); - debugfs_remove(data->debugfs); + debugfs_remove_recursive(data->debugfs); ieee80211_unregister_hw(data->hw); device_release_driver(data->dev); device_unregister(data->dev); @@ -2534,12 +2530,10 @@ static int __init init_mac80211_hwsim(void) data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); - data->debugfs_ps = debugfs_create_file("ps", 0666, - data->debugfs, data, - &hwsim_fops_ps); - data->debugfs_group = debugfs_create_file("group", 0666, - data->debugfs, data, - &hwsim_fops_group); + debugfs_create_file("ps", 0666, data->debugfs, data, + &hwsim_fops_ps); + debugfs_create_file("group", 0666, data->debugfs, data, + &hwsim_fops_group); tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, -- cgit v1.2.3 From bba05e3d5afb6ed31c00068f12418a9dacb42328 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 5 Nov 2013 13:03:53 +0100 Subject: mac80211_hwsim: Add iface comb for DFS Add iface combination that will allow DFS support. Add also debugfs dfs_simulate_radar file that can be used to simulate radar event. This could be useful for mac80211/cfg80211/ regulatory/hostap code testing without real HW. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 50 +++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 76b362ed76bd..bad66e3cdd12 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1889,6 +1889,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val) DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, "%llu\n"); +static int hwsim_write_simulate_radar(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + + ieee80211_radar_detected(data->hw); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, + hwsim_write_simulate_radar, "%llu\n"); static int hwsim_fops_group_read(void *dat, u64 *val) { @@ -2190,11 +2201,28 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, }; -static struct ieee80211_iface_combination hwsim_if_comb = { - .limits = hwsim_if_limits, - .n_limits = ARRAY_SIZE(hwsim_if_limits), - .max_interfaces = 2048, - .num_different_channels = 1, +static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { + { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, +}; + +static struct ieee80211_iface_combination hwsim_if_comb[] = { + { + .limits = hwsim_if_limits, + .n_limits = ARRAY_SIZE(hwsim_if_limits), + .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 int __init init_mac80211_hwsim(void) @@ -2212,7 +2240,7 @@ static int __init init_mac80211_hwsim(void) return -EINVAL; if (channels > 1) { - hwsim_if_comb.num_different_channels = channels; + hwsim_if_comb[0].num_different_channels = channels; mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; mac80211_hwsim_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan; @@ -2292,13 +2320,15 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->n_addresses = 2; hw->wiphy->addresses = data->addresses; - hw->wiphy->iface_combinations = &hwsim_if_comb; - hw->wiphy->n_iface_combinations = 1; + hw->wiphy->iface_combinations = hwsim_if_comb; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); if (channels > 1) { 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; } INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); @@ -2534,6 +2564,10 @@ static int __init init_mac80211_hwsim(void) &hwsim_fops_ps); debugfs_create_file("group", 0666, data->debugfs, data, &hwsim_fops_group); + if (channels == 1) + debugfs_create_file("dfs_simulate_radar", 0222, + data->debugfs, + data, &hwsim_simulate_radar); tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, -- cgit v1.2.3 From c17aa52c5bf571533cc8561292f7316b9216eddc Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Tue, 5 Nov 2013 13:03:54 +0100 Subject: mac80211_hwsim: VHT add 160MHz width support Add 160MHz width support. This could be usefull for testing VHT160 DFS functionality. This could be also usefull in the future when DFS and non-DFS channels could be mixed. Signed-off-by: Janusz Dziedzic Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bad66e3cdd12..bd7dd0d242d6 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2412,6 +2412,7 @@ static int __init init_mac80211_hwsim(void) 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 | -- cgit v1.2.3 From 3751c4edc6275e345d5978b1cb92265945399f69 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Mon, 11 Nov 2013 13:29:33 +0100 Subject: mac80211_hwsim: claim CCK support for HT clients Signed-off-by: Karl Beldan Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bd7dd0d242d6..8c7f4ab70d29 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2352,7 +2352,8 @@ static int __init init_mac80211_hwsim(void) IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_QUEUE_CONTROL; + IEEE80211_HW_QUEUE_CONTROL | + IEEE80211_HW_SUPPORTS_HT_CCK_RATES; if (rctbl) hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; -- cgit v1.2.3 From a2f73b6c5db3c272d87eaebb5bed355d75a0f25f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 11 Nov 2013 22:15:29 +0100 Subject: cfg80211: move regulatory flags to their own variable We'll expand this later, this will make it easier to classify and review what things are related to regulatory or not. Coccinelle only missed 4 hits, which I had to do manually, supplying the SmPL in case of merge conflicts. @@ struct wiphy *wiphy; @@ -wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY +wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG @@ expression e; @@ -e->flags |= WIPHY_FLAG_CUSTOM_REGULATORY +e->regulatory_flags |= REGULATORY_CUSTOM_REG @@ struct wiphy *wiphy; @@ -wiphy->flags &= ~WIPHY_FLAG_CUSTOM_REGULATORY +wiphy->regulatory_flags &= ~REGULATORY_CUSTOM_REG @@ struct wiphy *wiphy; @@ -wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY +wiphy->regulatory_flags & REGULATORY_CUSTOM_REG @@ struct wiphy *wiphy; @@ -wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY +wiphy->regulatory_flags |= REGULATORY_STRICT_REG @@ expression e; @@ -e->flags |= WIPHY_FLAG_STRICT_REGULATORY +e->regulatory_flags |= REGULATORY_STRICT_REG @@ struct wiphy *wiphy; @@ -wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY +wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG @@ struct wiphy *wiphy; @@ -wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY +wiphy->regulatory_flags & REGULATORY_STRICT_REG @@ struct wiphy *wiphy; @@ -wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS +wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS @@ expression e; @@ -e->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS +e->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS @@ struct wiphy *wiphy; @@ -wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS +wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS @@ struct wiphy *wiphy; @@ -wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS +wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS Generated-by: Coccinelle SmPL Cc: Julia Lawall Cc: Peter Senna Tschudin Cc: Mihir Shete Cc: Henri Bahini Cc: Tushnim Bhattacharyya Signed-off-by: Luis R. Rodriguez [fix up whitespace damage, overly long lines] Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/regd.c | 4 +- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 2 +- drivers/net/wireless/brcm80211/brcmsmac/channel.c | 4 +- drivers/net/wireless/iwlegacy/3945-mac.c | 6 +-- drivers/net/wireless/iwlegacy/4965-mac.c | 6 +-- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 6 +-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 +-- drivers/net/wireless/mac80211_hwsim.c | 25 +++++---- drivers/net/wireless/mwifiex/cfg80211.c | 5 +- drivers/net/wireless/rtlwifi/regd.c | 6 +-- include/net/cfg80211.h | 33 +++--------- include/net/regulatory.h | 59 +++++++++++++++++----- net/wireless/core.c | 2 +- net/wireless/reg.c | 32 ++++++------ 14 files changed, 108 insertions(+), 88 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e93e517a699f..aba782cd09a2 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -601,7 +601,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; - wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + wiphy->regulatory_flags |= REGULATORY_STRICT_REG; if (ath_is_world_regd(reg)) { /* @@ -609,7 +609,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; } else { /* * This gets applied in the case of the absence of CRDA, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index b6a09f97f9a3..1850efa83cf8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -4341,7 +4341,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) wiphy->max_remain_on_channel_duration = 5000; brcmf_wiphy_pno_params(wiphy); brcmf_dbg(INFO, "Registering custom regulatory\n"); - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom); err = wiphy_register(wiphy); if (err < 0) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 7d8f3fd69a87..ef05df04136b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -766,8 +766,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc) } wlc->wiphy->reg_notifier = brcms_reg_notifier; - wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_STRICT_REGULATORY; + wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_STRICT_REG; wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain); brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER); } diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 5a66595b0faf..5c3bcedd679b 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3575,9 +3575,9 @@ il3945_setup_mac(struct il_priv *il) hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= - WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 1c5f8cdbd3a5..43f488a8cda2 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -5778,9 +5778,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= - WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; /* * For now, disable PS by default because it affects diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index cae4d3182e33..217f1ca321a0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -155,9 +155,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, ARRAY_SIZE(iwlagn_iface_combinations_dualmode); } - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; #ifdef CONFIG_PM_SLEEP if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len && diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 74bc2c8af06d..b56c989ad784 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -199,9 +199,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_DISABLE_BEACON_HINTS | - WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; hw->wiphy->n_iface_combinations = diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 8c7f4ab70d29..bcc7d8208f23 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2456,46 +2456,53 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_WORLD_ROAM: if (i == 0) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } break; case HWSIM_REGTEST_CUSTOM_WORLD: - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); break; case HWSIM_REGTEST_CUSTOM_WORLD_2: if (i == 0) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } break; case HWSIM_REGTEST_STRICT_ALL: - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; break; case HWSIM_REGTEST_STRICT_FOLLOW: case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: if (i == 0) - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_STRICT_REG; break; case HWSIM_REGTEST_ALL: if (i == 0) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_01); } else if (i == 1) { - hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG; wiphy_apply_custom_regulatory(hw->wiphy, &hwsim_world_regdom_custom_02); } else if (i == 4) - hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + hw->wiphy->regulatory_flags |= + REGULATORY_STRICT_REG; break; default: break; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 7f68943f02c2..d6d1d91a26dc 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2687,9 +2687,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_CUSTOM_REGULATORY | - WIPHY_FLAG_STRICT_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wiphy->regulatory_flags |= + REGULATORY_CUSTOM_REG | + REGULATORY_STRICT_REG; wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom); diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 8453c53143f5..89e36568e70f 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -344,9 +344,9 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, wiphy->reg_notifier = reg_notifier; - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; - wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; - wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG; + wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; regd = _rtl_regdomain_select(reg); wiphy_apply_custom_regulatory(wiphy, regd); diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 968f2ad40ccd..bacc5033f0b6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2437,29 +2437,6 @@ struct cfg80211_ops { /** * enum wiphy_flags - wiphy capability flags * - * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device - * has its own custom regulatory domain and cannot identify the - * ISO / IEC 3166 alpha2 it belongs to. When this is enabled - * we will disregard the first regulatory hint (when the - * initiator is %REGDOM_SET_BY_CORE). Drivers that use - * wiphy_apply_custom_regulatory() should have this flag set - * or the regulatory core will set it for wiphy. - * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will - * ignore regulatory domain settings until it gets its own regulatory - * domain via its regulatory_hint() unless the regulatory hint is - * from a country IE. After its gets its own regulatory domain it will - * only allow further regulatory domain settings to further enhance - * compliance. For example if channel 13 and 14 are disabled by this - * regulatory domain no user regulatory domain can enable these channels - * at a later time. This can be used for devices which do not have - * calibration information guaranteed for frequencies or settings - * outside of its regulatory domain. If used in combination with - * WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings - * will be followed. - * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure - * that passive scan flags and beaconing flags may not be lifted by - * cfg80211 due to regulatory beacon hints. For more information on beacon - * hints read the documenation for regulatory_hint_found_beacon() * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this * wiphy at all * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled @@ -2498,9 +2475,9 @@ struct cfg80211_ops { * beaconing mode (AP, IBSS, Mesh, ...). */ enum wiphy_flags { - WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), - WIPHY_FLAG_STRICT_REGULATORY = BIT(1), - WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2), + /* use hole at 0 */ + /* use hole at 1 */ + /* use hole at 2 */ WIPHY_FLAG_NETNS_OK = BIT(3), WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), WIPHY_FLAG_4ADDR_AP = BIT(5), @@ -2722,6 +2699,8 @@ struct wiphy_coalesce_support { * @software_iftypes: bitmask of software interface types, these are not * subject to any restrictions since they are purely managed in SW. * @flags: wiphy flags, see &enum wiphy_flags + * @regulatory_flags: wiphy regulatory flags, see + * &enum ieee80211_regulatory_flags * @features: features advertised to nl80211, see &enum nl80211_feature_flags. * @bss_priv_size: each BSS struct has private data allocated with it, * this variable determines its size @@ -2810,7 +2789,7 @@ struct wiphy { u16 max_acl_mac_addrs; - u32 flags, features; + u32 flags, regulatory_flags, features; u32 ap_sme_capa; diff --git a/include/net/regulatory.h b/include/net/regulatory.h index f17ed590d64a..a6a20e2a54c4 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -38,17 +38,17 @@ enum environment_cap { * * @rcu_head: RCU head struct used to free the request * @wiphy_idx: this is set if this request's initiator is - * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This - * can be used by the wireless core to deal with conflicts - * and potentially inform users of which devices specifically - * cased the conflicts. + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. * @initiator: indicates who sent this request, could be any of - * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) + * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*) * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested - * regulatory domain. We have a few special codes: - * 00 - World regulatory domain - * 99 - built by driver but a specific alpha2 cannot be determined - * 98 - result of an intersection between two regulatory domains + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains * 97 - regulatory domain has not yet been configured * @dfs_region: If CRDA responded with a regulatory domain that requires * DFS master operation on a known DFS region (NL80211_DFS_*), @@ -59,8 +59,8 @@ enum environment_cap { * of hint passed. This could be any of the %NL80211_USER_REG_HINT_* * types. * @intersect: indicates whether the wireless core should intersect - * the requested regulatory domain with the presently set regulatory - * domain. + * the requested regulatory domain with the presently set regulatory + * domain. * @processed: indicates whether or not this requests has already been * processed. When the last request is processed it means that the * currently regulatory domain set on cfg80211 is updated from @@ -68,9 +68,9 @@ enum environment_cap { * the last request is not yet processed we must yield until it * is processed before processing any new requests. * @country_ie_checksum: checksum of the last processed and accepted - * country IE + * country IE * @country_ie_env: lets us know if the AP is telling us we are outdoor, - * indoor, or if it doesn't matter + * indoor, or if it doesn't matter * @list: used to insert into the reg_requests_list linked list */ struct regulatory_request { @@ -86,6 +86,39 @@ struct regulatory_request { struct list_head list; }; +/** + * enum ieee80211_regulatory_flags - device regulatory flags + * + * @REGULATORY_CUSTOM_REG: tells us the driver for this device + * has its own custom regulatory domain and cannot identify the + * ISO / IEC 3166 alpha2 it belongs to. When this is enabled + * we will disregard the first regulatory hint (when the + * initiator is %REGDOM_SET_BY_CORE). Drivers that use + * wiphy_apply_custom_regulatory() should have this flag set + * or the regulatory core will set it for the wiphy. + * @REGULATORY_STRICT_REG: tells us the driver for this device will + * ignore regulatory domain settings until it gets its own regulatory + * domain via its regulatory_hint() unless the regulatory hint is + * from a country IE. After its gets its own regulatory domain it will + * only allow further regulatory domain settings to further enhance + * compliance. For example if channel 13 and 14 are disabled by this + * regulatory domain no user regulatory domain can enable these channels + * at a later time. This can be used for devices which do not have + * calibration information guaranteed for frequencies or settings + * outside of its regulatory domain. If used in combination with + * REGULATORY_FLAG_CUSTOM_REG the inspected country IE power settings + * will be followed. + * @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to + * ensure that passive scan flags and beaconing flags may not be lifted by + * cfg80211 due to regulatory beacon hints. For more information on beacon + * hints read the documenation for regulatory_hint_found_beacon() + */ +enum ieee80211_regulatory_flags { + REGULATORY_CUSTOM_REG = BIT(0), + REGULATORY_STRICT_REG = BIT(1), + REGULATORY_DISABLE_BEACON_HINTS = BIT(2), +}; + struct ieee80211_freq_range { u32 start_freq_khz; u32 end_freq_khz; diff --git a/net/wireless/core.c b/net/wireless/core.c index 9dca0925a1a9..fc968c861ee4 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -586,7 +586,7 @@ int wiphy_register(struct wiphy *wiphy) if (IS_ERR(rdev->wiphy.debugfsdir)) rdev->wiphy.debugfsdir = NULL; - if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { struct regulatory_request request; request.wiphy_idx = get_wiphy_idx(wiphy); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index a75c5eddd25f..e44b4bb20b92 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -868,7 +868,7 @@ static void handle_channel(struct wiphy *wiphy, if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { REG_DBG_PRINT("Disabling freq %d MHz for good\n", chan->center_freq); chan->orig_flags |= IEEE80211_CHAN_DISABLED; @@ -895,7 +895,7 @@ static void handle_channel(struct wiphy *wiphy, if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && request_wiphy && request_wiphy == wiphy && - request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { + request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { /* * This guarantees the driver's requested regulatory domain * will always be used as a base for further regulatory @@ -922,12 +922,12 @@ static void handle_channel(struct wiphy *wiphy, if (chan->orig_mpwr) { /* * Devices that have their own custom regulatory domain - * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the + * but also use REGULATORY_STRICT_REG will follow the * passed country IE power settings. */ if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && - wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG && + wiphy->regulatory_flags & REGULATORY_STRICT_REG) chan->max_power = chan->max_reg_power; else chan->max_power = min(chan->orig_mpwr, @@ -997,8 +997,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) { - if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && - !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) + if (wiphy->regulatory_flags & REGULATORY_STRICT_REG && + !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)) return true; return false; } @@ -1016,7 +1016,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, } if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { REG_DBG_PRINT("Ignoring regulatory request set by %s " "since the driver uses its own custom " "regulatory domain\n", @@ -1054,7 +1054,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) return true; if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) return true; return false; @@ -1082,7 +1082,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, if (!reg_is_world_roaming(wiphy)) return; - if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS) + if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS) return; chan_before.center_freq = chan->center_freq; @@ -1242,7 +1242,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, * as some drivers used this to restore its orig_* reg domain. */ if (initiator == NL80211_REGDOM_SET_BY_CORE && - wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) + wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) reg_call_notifier(wiphy, lr); return; } @@ -1328,9 +1328,9 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, enum ieee80211_band band; unsigned int bands_set = 0; - WARN(!(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY), - "wiphy should have WIPHY_FLAG_CUSTOM_REGULATORY\n"); - wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG), + "wiphy should have REGULATORY_CUSTOM_REG\n"); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!wiphy->bands[band]) @@ -1659,7 +1659,7 @@ 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->flags & WIPHY_FLAG_STRICT_REGULATORY) + wiphy->regulatory_flags & REGULATORY_STRICT_REG) wiphy_update_regulatory(wiphy, reg_request->initiator); } @@ -1986,7 +1986,7 @@ static void restore_regulatory_settings(bool reset_user) world_alpha2[1] = cfg80211_world_regdom->alpha2[1]; list_for_each_entry(rdev, &cfg80211_rdev_list, list) { - if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY) + if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG) restore_custom_reg_settings(&rdev->wiphy); } -- cgit v1.2.3 From 1d940aaab881b0ee62557ffbaad877ac5a1b51db Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 18 Nov 2013 17:23:26 +0100 Subject: mac80211_hwsim: use CLOCK_MONOTONIC_RAW The beacon timers really shouldn't use any clock that is subject to adjustments from userspace, particularly not CLOCK_REALTIME. Use CLOCK_MONOTONIC_RAW instead. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bcc7d8208f23..ab875566c744 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2580,7 +2580,7 @@ static int __init init_mac80211_hwsim(void) tasklet_hrtimer_init(&data->beacon_timer, mac80211_hwsim_beacon, - CLOCK_REALTIME, HRTIMER_MODE_ABS); + CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); list_add_tail(&data->list, &hwsim_radios); } -- cgit v1.2.3 From 79012f8bed417847ec028bd67547eae4eb832205 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 21:53:27 +0100 Subject: mac80211_hwsim: fix a print message The prefix should be mac80211_hwsim, not mac_80211_hwsim. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9c0cc8ded021..9e7d7df03a47 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2618,7 +2618,7 @@ static int __init init_mac80211_hwsim(void) return 0; failed_nl: - printk(KERN_DEBUG "mac_80211_hwsim: failed initializing netlink\n"); + printk(KERN_DEBUG "mac80211_hwsim: failed initializing netlink\n"); return err; failed_mon: -- cgit v1.2.3 From 685328b296acc810541d2532957912690273c64a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:24:00 +0100 Subject: mac80211: remove channel_change_time This value is no longer used by mac80211, and practically no driver ever set it to a correct value anyway, so remove it. Signed-off-by: Johannes Berg --- drivers/net/wireless/adm8211.c | 1 - drivers/net/wireless/at76c50x-usb.c | 1 - drivers/net/wireless/ath/ath10k/mac.c | 1 - drivers/net/wireless/ath/ath5k/base.c | 1 - drivers/net/wireless/ath/ath9k/htc_drv_init.c | 1 - drivers/net/wireless/ath/ath9k/init.c | 1 - drivers/net/wireless/ath/carl9170/main.c | 12 ------------ drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 1 - drivers/net/wireless/cw1200/main.c | 1 - drivers/net/wireless/mac80211_hwsim.c | 1 - drivers/net/wireless/mwl8k.c | 2 -- drivers/net/wireless/p54/main.c | 1 - drivers/net/wireless/rtlwifi/base.c | 1 - drivers/net/wireless/ti/wl1251/main.c | 1 - drivers/net/wireless/ti/wlcore/main.c | 1 - drivers/staging/winbond/wbusb.c | 1 - include/net/mac80211.h | 3 --- 17 files changed, 31 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index cfce83e1f273..54afde0463dd 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1866,7 +1866,6 @@ static int adm8211_probe(struct pci_dev *pdev, dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - dev->channel_change_time = 1000; dev->max_signal = 100; /* FIXME: find better value */ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 34c8a33cac06..8cfd1d6841b1 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -2112,7 +2112,6 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev) priv->pm_period = 0; /* unit us */ - priv->hw->channel_change_time = 100000; return priv; } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ce9ef3499ecb..747c8bd74980 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3704,7 +3704,6 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->vif_data_size = sizeof(struct ath10k_vif); - ar->hw->channel_change_time = 5000; ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 69f58b073e85..fe6878b4ecd0 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2549,7 +2549,6 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) hw->wiphy->available_antennas_rx = 0x3; hw->extra_tx_headroom = 2; - hw->channel_change_time = 5000; /* * Mark the device as detached to avoid processing diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index c3676bf1d6c4..bcdb50af56d3 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -748,7 +748,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; hw->queues = 4; - hw->channel_change_time = 5000; hw->max_listen_interval = 1; hw->vif_data_size = sizeof(struct ath9k_htc_vif); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 609b7e13f3f0..d8787692c9d4 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -950,7 +950,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->queues = 4; hw->max_rates = 4; - hw->channel_change_time = 5000; hw->max_listen_interval = 1; hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 349fa22a921a..5ab68fddf7ba 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1968,18 +1968,6 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) return -ENOMEM; ar->num_channels = chans; - /* - * I measured this, a bandswitch takes roughly - * 135 ms and a frequency switch about 80. - * - * FIXME: measure these values again once EEPROM settings - * are used, that will influence them! - */ - if (bands == 2) - ar->hw->channel_change_time = 135 * 1000; - else - ar->hw->channel_change_time = 80 * 1000; - regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); /* second part of wiphy init */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index e71ce8c842a2..925034b80e9c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1071,7 +1071,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw) hw->max_rates = 2; /* Primary rate and 1 fallback rate */ /* channel change time is dependent on chip and band */ - hw->channel_change_time = 7 * 1000; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_ADHOC); diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c index 090f01577dd2..1be819dfac63 100644 --- a/drivers/net/wireless/cw1200/main.c +++ b/drivers/net/wireless/cw1200/main.c @@ -302,7 +302,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - hw->channel_change_time = 1000; /* TODO: find actual value */ hw->queues = 4; priv->rts_threshold = -1; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9e7d7df03a47..59c65c37bccd 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2341,7 +2341,6 @@ static int __init init_mac80211_hwsim(void) INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); - hw->channel_change_time = 1; hw->queues = 5; hw->offchannel_tx_hw_queue = 4; hw->wiphy->interface_modes = diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b953ad621e0b..721c738a7dd8 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -5893,8 +5893,6 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; - hw->channel_change_time = 10; - hw->queues = MWL8K_TX_WMM_QUEUES; /* Set rssi values to dBm */ diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 067e6f2fd050..b61fefad2205 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -757,7 +757,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MESH_POINT); - dev->channel_change_time = 1000; /* TODO: find actual value */ priv->beacon_req_id = cpu_to_le32(0); priv->tx_stats[P54_QUEUE_BEACON].limit = 1; priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1; diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index fcf9b621918c..2cfb6d4514cd 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -353,7 +353,6 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* TODO: Correct this value for our hw */ /* TODO: define these hard code value */ - hw->channel_change_time = 100; hw->max_listen_interval = 10; hw->max_rate_tries = 4; /* hw->max_rates = 1; */ diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 3291ffa95273..ee4ec4e5660d 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1347,7 +1347,6 @@ int wl1251_init_ieee80211(struct wl1251 *wl) /* unit us */ /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS | diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index e9da47cead58..18a009e593c7 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5710,7 +5710,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) /* unit us */ /* FIXME: find a proper value */ - wl->hw->channel_change_time = 10000; wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval; wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | diff --git a/drivers/staging/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c index 07891a3e316e..0d29624416c3 100644 --- a/drivers/staging/winbond/wbusb.c +++ b/drivers/staging/winbond/wbusb.c @@ -788,7 +788,6 @@ static int wb35_probe(struct usb_interface *intf, dev->flags = IEEE80211_HW_SIGNAL_UNSPEC; dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - dev->channel_change_time = 1000; dev->max_signal = 100; dev->queues = 1; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f838af816b56..25b18877747f 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1616,8 +1616,6 @@ enum ieee80211_hw_flags { * @extra_beacon_tailroom: tailroom to reserve in each beacon tx skb. * Can be used by drivers to add extra IEs. * - * @channel_change_time: time (in microseconds) it takes to change channels. - * * @max_signal: Maximum value for signal (rssi) in RX information, used * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB * @@ -1699,7 +1697,6 @@ struct ieee80211_hw { u32 flags; unsigned int extra_tx_headroom; unsigned int extra_beacon_tailroom; - int channel_change_time; int vif_data_size; int sta_data_size; int chanctx_data_size; -- cgit v1.2.3 From cf7a6b2d5bd73acd8e3a78cf03259489bd83498a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 21:55:14 +0100 Subject: mac80211_hwsim: clean up netlink exit code There's no need to print a message, and genl_unregister_family() can't really fail so remove the error message there as well. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 59c65c37bccd..03d7b1d360ae 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2180,20 +2180,14 @@ failure: static void hwsim_exit_netlink(void) { - int ret; - /* userspace test API hasn't been adjusted for multi-channel */ if (channels > 1) return; - printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); /* unregister the notifier */ netlink_unregister_notifier(&hwsim_netlink_notifier); /* unregister the family */ - ret = genl_unregister_family(&hwsim_genl_family); - if (ret) - printk(KERN_DEBUG "mac80211_hwsim: " - "unregister family %i\n", ret); + genl_unregister_family(&hwsim_genl_family); } static const struct ieee80211_iface_limit hwsim_if_limits[] = { -- cgit v1.2.3 From 38ed5048fe84d6048835916f298eaa623f59ace4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:11:06 +0100 Subject: mac80211_hwsim: prepare for different channel support Prepare the code to support, in theory, different devices with a different number of channels supported. Right now this doesn't really change anything, but will allow for dynamic device registration in the future. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 67 +++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 03d7b1d360ae..4e9422454fd7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -332,8 +332,10 @@ struct mac80211_hwsim_data { struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; + struct ieee80211_iface_combination if_combination; struct mac_address addresses[2]; + int channels; struct ieee80211_channel *tmp_chan; struct delayed_work roc_done; @@ -878,7 +880,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, return; } - if (channels == 1) { + if (data->channels == 1) { channel = data->channel; } else if (txi->hw_queue == 4) { channel = data->tmp_chan; @@ -1141,7 +1143,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) data->channel = conf->chandef.chan; - WARN_ON(data->channel && channels > 1); + WARN_ON(data->channel && data->channels > 1); data->power_level = conf->power_level; if (!data->started || !data->beacon_int) @@ -1700,8 +1702,7 @@ static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, hwsim_check_chanctx_magic(ctx); } -static struct ieee80211_ops mac80211_hwsim_ops = -{ +static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, .start = mac80211_hwsim_start, .stop = mac80211_hwsim_stop, @@ -1726,6 +1727,7 @@ static struct ieee80211_ops mac80211_hwsim_ops = .set_tsf = mac80211_hwsim_set_tsf, }; +static struct ieee80211_ops mac80211_hwsim_mchan_ops; static void mac80211_hwsim_free(void) { @@ -2206,7 +2208,7 @@ static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, }; -static struct ieee80211_iface_combination hwsim_if_comb[] = { +static const struct ieee80211_iface_combination hwsim_if_comb[] = { { .limits = hwsim_if_limits, .n_limits = ARRAY_SIZE(hwsim_if_limits), @@ -2233,6 +2235,7 @@ static int __init init_mac80211_hwsim(void) struct mac80211_hwsim_data *data; struct ieee80211_hw *hw; enum ieee80211_band band; + const struct ieee80211_ops *ops; if (radios < 1 || radios > 100) return -EINVAL; @@ -2240,28 +2243,20 @@ static int __init init_mac80211_hwsim(void) if (channels < 1) return -EINVAL; - if (channels > 1) { - hwsim_if_comb[0].num_different_channels = channels; - mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; - mac80211_hwsim_ops.cancel_hw_scan = - mac80211_hwsim_cancel_hw_scan; - mac80211_hwsim_ops.sw_scan_start = NULL; - mac80211_hwsim_ops.sw_scan_complete = NULL; - mac80211_hwsim_ops.remain_on_channel = - mac80211_hwsim_roc; - mac80211_hwsim_ops.cancel_remain_on_channel = - mac80211_hwsim_croc; - mac80211_hwsim_ops.add_chanctx = - mac80211_hwsim_add_chanctx; - mac80211_hwsim_ops.remove_chanctx = - mac80211_hwsim_remove_chanctx; - mac80211_hwsim_ops.change_chanctx = - mac80211_hwsim_change_chanctx; - mac80211_hwsim_ops.assign_vif_chanctx = - mac80211_hwsim_assign_vif_chanctx; - mac80211_hwsim_ops.unassign_vif_chanctx = - mac80211_hwsim_unassign_vif_chanctx; - } + mac80211_hwsim_mchan_ops = mac80211_hwsim_ops; + mac80211_hwsim_mchan_ops.hw_scan = mac80211_hwsim_hw_scan; + mac80211_hwsim_mchan_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan; + mac80211_hwsim_mchan_ops.sw_scan_start = NULL; + mac80211_hwsim_mchan_ops.sw_scan_complete = NULL; + mac80211_hwsim_mchan_ops.remain_on_channel = mac80211_hwsim_roc; + mac80211_hwsim_mchan_ops.cancel_remain_on_channel = mac80211_hwsim_croc; + mac80211_hwsim_mchan_ops.add_chanctx = mac80211_hwsim_add_chanctx; + mac80211_hwsim_mchan_ops.remove_chanctx = mac80211_hwsim_remove_chanctx; + mac80211_hwsim_mchan_ops.change_chanctx = mac80211_hwsim_change_chanctx; + mac80211_hwsim_mchan_ops.assign_vif_chanctx = + mac80211_hwsim_assign_vif_chanctx; + mac80211_hwsim_mchan_ops.unassign_vif_chanctx = + mac80211_hwsim_unassign_vif_chanctx; spin_lock_init(&hwsim_radio_lock); INIT_LIST_HEAD(&hwsim_radios); @@ -2282,7 +2277,10 @@ static int __init init_mac80211_hwsim(void) for (i = 0; i < radios; i++) { printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", i); - hw = ieee80211_alloc_hw(sizeof(*data), &mac80211_hwsim_ops); + ops = &mac80211_hwsim_ops; + if (channels > 1) + ops = &mac80211_hwsim_mchan_ops; + hw = ieee80211_alloc_hw(sizeof(*data), ops); if (!hw) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " "failed\n"); @@ -2321,15 +2319,22 @@ static int __init init_mac80211_hwsim(void) hw->wiphy->n_addresses = 2; hw->wiphy->addresses = data->addresses; - hw->wiphy->iface_combinations = hwsim_if_comb; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); + data->channels = channels; - if (channels > 1) { + if (data->channels > 1) { 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]; + data->if_combination.num_different_channels = + data->channels; + } else { + hw->wiphy->iface_combinations = hwsim_if_comb; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(hwsim_if_comb); } INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); -- cgit v1.2.3 From 3a8cc5e73f7105faf32fb8df57ba3e7b967e1982 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:26:23 +0100 Subject: mac80211_hwsim: remove regtest for now The regtest thing worked based on the radio loop, but with more dynamic radio registration that loop won't really exist as is. We can add it back later with proper dynamic code. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 220 ---------------------------------- 1 file changed, 220 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4e9422454fd7..55cdfd6a40e8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -57,112 +57,6 @@ static bool rctbl = false; module_param(rctbl, bool, 0444); MODULE_PARM_DESC(rctbl, "Handle rate control table"); -/** - * enum hwsim_regtest - the type of regulatory tests we offer - * - * These are the different values you can use for the regtest - * module parameter. This is useful to help test world roaming - * and the driver regulatory_hint() call and combinations of these. - * If you want to do specific alpha2 regulatory domain tests simply - * use the userspace regulatory request as that will be respected as - * well without the need of this module parameter. This is designed - * only for testing the driver regulatory request, world roaming - * and all possible combinations. - * - * @HWSIM_REGTEST_DISABLED: No regulatory tests are performed, - * this is the default value. - * @HWSIM_REGTEST_DRIVER_REG_FOLLOW: Used for testing the driver regulatory - * hint, only one driver regulatory hint will be sent as such the - * secondary radios are expected to follow. - * @HWSIM_REGTEST_DRIVER_REG_ALL: Used for testing the driver regulatory - * request with all radios reporting the same regulatory domain. - * @HWSIM_REGTEST_DIFF_COUNTRY: Used for testing the drivers calling - * different regulatory domains requests. Expected behaviour is for - * an intersection to occur but each device will still use their - * respective regulatory requested domains. Subsequent radios will - * use the resulting intersection. - * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We accomplish - * this by using a custom beacon-capable regulatory domain for the first - * radio. All other device world roam. - * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory - * domain requests. All radios will adhere to this custom world regulatory - * domain. - * @HWSIM_REGTEST_CUSTOM_WORLD_2: Used for testing 2 custom world regulatory - * domain requests. The first radio will adhere to the first custom world - * regulatory domain, the second one to the second custom world regulatory - * domain. All other devices will world roam. - * @HWSIM_REGTEST_STRICT_FOLLOW_: Used for testing strict regulatory domain - * settings, only the first radio will send a regulatory domain request - * and use strict settings. The rest of the radios are expected to follow. - * @HWSIM_REGTEST_STRICT_ALL: Used for testing strict regulatory domain - * settings. All radios will adhere to this. - * @HWSIM_REGTEST_STRICT_AND_DRIVER_REG: Used for testing strict regulatory - * domain settings, combined with secondary driver regulatory domain - * settings. The first radio will get a strict regulatory domain setting - * using the first driver regulatory request and the second radio will use - * non-strict settings using the second driver regulatory request. All - * other devices should follow the intersection created between the - * first two. - * @HWSIM_REGTEST_ALL: Used for testing every possible mix. You will need - * at least 6 radios for a complete test. We will test in this order: - * 1 - driver custom world regulatory domain - * 2 - second custom world regulatory domain - * 3 - first driver regulatory domain request - * 4 - second driver regulatory domain request - * 5 - strict regulatory domain settings using the third driver regulatory - * domain request - * 6 and on - should follow the intersection of the 3rd, 4rth and 5th radio - * regulatory requests. - */ -enum hwsim_regtest { - HWSIM_REGTEST_DISABLED = 0, - HWSIM_REGTEST_DRIVER_REG_FOLLOW = 1, - HWSIM_REGTEST_DRIVER_REG_ALL = 2, - HWSIM_REGTEST_DIFF_COUNTRY = 3, - HWSIM_REGTEST_WORLD_ROAM = 4, - HWSIM_REGTEST_CUSTOM_WORLD = 5, - HWSIM_REGTEST_CUSTOM_WORLD_2 = 6, - HWSIM_REGTEST_STRICT_FOLLOW = 7, - HWSIM_REGTEST_STRICT_ALL = 8, - HWSIM_REGTEST_STRICT_AND_DRIVER_REG = 9, - HWSIM_REGTEST_ALL = 10, -}; - -/* Set to one of the HWSIM_REGTEST_* values above */ -static int regtest = HWSIM_REGTEST_DISABLED; -module_param(regtest, int, 0444); -MODULE_PARM_DESC(regtest, "The type of regulatory test we want to run"); - -static const char *hwsim_alpha2s[] = { - "FI", - "AL", - "US", - "DE", - "JP", - "AL", -}; - -static const struct ieee80211_regdomain hwsim_world_regdom_custom_01 = { - .n_reg_rules = 4, - .alpha2 = "99", - .reg_rules = { - REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), - REG_RULE(2484-10, 2484+10, 40, 0, 20, 0), - REG_RULE(5150-10, 5240+10, 40, 0, 30, 0), - REG_RULE(5745-10, 5825+10, 40, 0, 30, 0), - } -}; - -static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { - .n_reg_rules = 2, - .alpha2 = "99", - .reg_rules = { - REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), - REG_RULE(5725-10, 5850+10, 40, 0, 30, - NL80211_RRF_NO_IR), - } -}; - struct hwsim_vif_priv { u32 magic; u8 bssid[ETH_ALEN]; @@ -2448,74 +2342,6 @@ static int __init init_mac80211_hwsim(void) hw->max_rates = 4; hw->max_rate_tries = 11; - /* Work to be done prior to ieee80211_register_hw() */ - switch (regtest) { - case HWSIM_REGTEST_DISABLED: - case HWSIM_REGTEST_DRIVER_REG_FOLLOW: - case HWSIM_REGTEST_DRIVER_REG_ALL: - case HWSIM_REGTEST_DIFF_COUNTRY: - /* - * Nothing to be done for driver regulatory domain - * hints prior to ieee80211_register_hw() - */ - break; - case HWSIM_REGTEST_WORLD_ROAM: - if (i == 0) { - hw->wiphy->regulatory_flags |= - REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, - &hwsim_world_regdom_custom_01); - } - break; - case HWSIM_REGTEST_CUSTOM_WORLD: - hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, - &hwsim_world_regdom_custom_01); - break; - case HWSIM_REGTEST_CUSTOM_WORLD_2: - if (i == 0) { - hw->wiphy->regulatory_flags |= - REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, - &hwsim_world_regdom_custom_01); - } else if (i == 1) { - hw->wiphy->regulatory_flags |= - REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, - &hwsim_world_regdom_custom_02); - } - break; - case HWSIM_REGTEST_STRICT_ALL: - hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; - break; - case HWSIM_REGTEST_STRICT_FOLLOW: - case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: - if (i == 0) - hw->wiphy->regulatory_flags |= - REGULATORY_STRICT_REG; - break; - case HWSIM_REGTEST_ALL: - if (i == 0) { - hw->wiphy->regulatory_flags |= - REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, - &hwsim_world_regdom_custom_01); - } else if (i == 1) { - hw->wiphy->regulatory_flags |= - REGULATORY_CUSTOM_REG; - wiphy_apply_custom_regulatory(hw->wiphy, - &hwsim_world_regdom_custom_02); - } else if (i == 4) - hw->wiphy->regulatory_flags |= - REGULATORY_STRICT_REG; - break; - default: - break; - } - - /* give the regulatory workqueue a chance to run */ - if (regtest) - schedule_timeout_interruptible(1); err = ieee80211_register_hw(hw); if (err < 0) { printk(KERN_DEBUG "mac80211_hwsim: " @@ -2523,52 +2349,6 @@ static int __init init_mac80211_hwsim(void) goto failed_hw; } - /* Work to be done after to ieee80211_register_hw() */ - switch (regtest) { - case HWSIM_REGTEST_WORLD_ROAM: - case HWSIM_REGTEST_DISABLED: - break; - case HWSIM_REGTEST_DRIVER_REG_FOLLOW: - if (!i) - regulatory_hint(hw->wiphy, hwsim_alpha2s[0]); - break; - case HWSIM_REGTEST_DRIVER_REG_ALL: - case HWSIM_REGTEST_STRICT_ALL: - regulatory_hint(hw->wiphy, hwsim_alpha2s[0]); - break; - case HWSIM_REGTEST_DIFF_COUNTRY: - if (i < ARRAY_SIZE(hwsim_alpha2s)) - regulatory_hint(hw->wiphy, hwsim_alpha2s[i]); - break; - case HWSIM_REGTEST_CUSTOM_WORLD: - case HWSIM_REGTEST_CUSTOM_WORLD_2: - /* - * Nothing to be done for custom world regulatory - * domains after to ieee80211_register_hw - */ - break; - case HWSIM_REGTEST_STRICT_FOLLOW: - if (i == 0) - regulatory_hint(hw->wiphy, hwsim_alpha2s[0]); - break; - case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: - if (i == 0) - regulatory_hint(hw->wiphy, hwsim_alpha2s[0]); - else if (i == 1) - regulatory_hint(hw->wiphy, hwsim_alpha2s[1]); - break; - case HWSIM_REGTEST_ALL: - if (i == 2) - regulatory_hint(hw->wiphy, hwsim_alpha2s[0]); - else if (i == 3) - regulatory_hint(hw->wiphy, hwsim_alpha2s[1]); - else if (i == 4) - regulatory_hint(hw->wiphy, hwsim_alpha2s[2]); - break; - default: - break; - } - wiphy_debug(hw->wiphy, "hwaddr %pm registered\n", hw->wiphy->perm_addr); -- cgit v1.2.3 From f39c2bfa9a1e2bae726cce65d2d328652e81f0c2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:39:27 +0100 Subject: mac80211_hwsim: refactor radio registration In order to support dynamic radio registration in the future, refactor the actual registration into a new function with only minor cleanups. Since it had to change anyway, also clean up the init error paths. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 455 +++++++++++++++++----------------- 1 file changed, 225 insertions(+), 230 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 55cdfd6a40e8..23fa6ee8eefe 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2122,14 +2122,219 @@ static const struct ieee80211_iface_combination hwsim_if_comb[] = { } }; -static int __init init_mac80211_hwsim(void) +static int __init mac80211_hwsim_create_radio(int idx) { - int i, err = 0; + int err; u8 addr[ETH_ALEN]; struct mac80211_hwsim_data *data; struct ieee80211_hw *hw; enum ieee80211_band band; - const struct ieee80211_ops *ops; + const struct ieee80211_ops *ops = &mac80211_hwsim_ops; + + if (channels > 1) + ops = &mac80211_hwsim_mchan_ops; + hw = ieee80211_alloc_hw(sizeof(*data), ops); + if (!hw) { + printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); + err = -ENOMEM; + goto failed; + } + data = hw->priv; + data->hw = hw; + + data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); + if (IS_ERR(data->dev)) { + printk(KERN_DEBUG + "mac80211_hwsim: device_create failed (%ld)\n", + PTR_ERR(data->dev)); + err = -ENOMEM; + goto failed_drvdata; + } + data->dev->driver = &mac80211_hwsim_driver.driver; + err = device_bind_driver(data->dev); + if (err != 0) { + printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", + err); + goto failed_hw; + } + + skb_queue_head_init(&data->pending); + + SET_IEEE80211_DEV(hw, data->dev); + memset(addr, 0, ETH_ALEN); + addr[0] = 0x02; + addr[3] = idx >> 8; + addr[4] = idx; + memcpy(data->addresses[0].addr, addr, ETH_ALEN); + memcpy(data->addresses[1].addr, addr, ETH_ALEN); + data->addresses[1].addr[0] |= 0x40; + hw->wiphy->n_addresses = 2; + hw->wiphy->addresses = data->addresses; + + data->channels = channels; + + if (data->channels > 1) { + 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]; + data->if_combination.num_different_channels = data->channels; + } else { + hw->wiphy->iface_combinations = hwsim_if_comb; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); + } + + INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); + INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); + + hw->queues = 5; + hw->offchannel_tx_hw_queue = 4; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_P2P_DEVICE); + + hw->flags = IEEE80211_HW_MFP_CAPABLE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_STATIC_SMPS | + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_WANT_MONITOR_VIF | + IEEE80211_HW_QUEUE_CONTROL | + IEEE80211_HW_SUPPORTS_HT_CCK_RATES; + 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; + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + + /* ask mac80211 to reserve space for magic */ + hw->vif_data_size = sizeof(struct hwsim_vif_priv); + hw->sta_data_size = sizeof(struct hwsim_sta_priv); + hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); + + memcpy(data->channels_2ghz, hwsim_channels_2ghz, + sizeof(hwsim_channels_2ghz)); + memcpy(data->channels_5ghz, hwsim_channels_5ghz, + sizeof(hwsim_channels_5ghz)); + memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); + + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband = &data->bands[band]; + switch (band) { + case IEEE80211_BAND_2GHZ: + sband->channels = data->channels_2ghz; + sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); + sband->bitrates = data->rates; + sband->n_bitrates = ARRAY_SIZE(hwsim_rates); + break; + case IEEE80211_BAND_5GHZ: + sband->channels = data->channels_5ghz; + sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); + sband->bitrates = data->rates + 4; + sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; + break; + default: + continue; + } + + sband->ht_cap.ht_supported = true; + sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + sband->ht_cap.ampdu_factor = 0x3; + sband->ht_cap.ampdu_density = 0x6; + memset(&sband->ht_cap.mcs, 0, + sizeof(sband->ht_cap.mcs)); + sband->ht_cap.mcs.rx_mask[0] = 0xff; + sband->ht_cap.mcs.rx_mask[1] = 0xff; + sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + hw->wiphy->bands[band] = sband; + + sband->vht_cap.vht_supported = true; + 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 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_RXSTBC_2 | + IEEE80211_VHT_CAP_RXSTBC_3 | + IEEE80211_VHT_CAP_RXSTBC_4 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + sband->vht_cap.vht_mcs.rx_mcs_map = + cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); + sband->vht_cap.vht_mcs.tx_mcs_map = + sband->vht_cap.vht_mcs.rx_mcs_map; + } + + /* By default all radios belong to the first group */ + data->group = 1; + mutex_init(&data->mutex); + + /* Enable frame retransmissions for lossy channels */ + hw->max_rates = 4; + hw->max_rate_tries = 11; + + err = ieee80211_register_hw(hw); + if (err < 0) { + printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", + err); + goto failed_hw; + } + + wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); + + data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); + 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) + debugfs_create_file("dfs_simulate_radar", 0222, + data->debugfs, + data, &hwsim_simulate_radar); + + tasklet_hrtimer_init(&data->beacon_timer, + mac80211_hwsim_beacon, + CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); + + spin_lock_bh(&hwsim_radio_lock); + list_add_tail(&data->list, &hwsim_radios); + spin_unlock_bh(&hwsim_radio_lock); + + return 0; + +failed_hw: + device_unregister(data->dev); +failed_drvdata: + ieee80211_free_hw(hw); +failed: + return err; +} + +static int __init init_mac80211_hwsim(void) +{ + int i, err; if (radios < 1 || radios > 100) return -EINVAL; @@ -2162,256 +2367,46 @@ static int __init init_mac80211_hwsim(void) hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); if (IS_ERR(hwsim_class)) { err = PTR_ERR(hwsim_class); - goto failed_unregister_driver; + goto out_unregister_driver; } - memset(addr, 0, ETH_ALEN); - addr[0] = 0x02; - for (i = 0; i < radios; i++) { - printk(KERN_DEBUG "mac80211_hwsim: Initializing radio %d\n", - i); - ops = &mac80211_hwsim_ops; - if (channels > 1) - ops = &mac80211_hwsim_mchan_ops; - hw = ieee80211_alloc_hw(sizeof(*data), ops); - if (!hw) { - printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw " - "failed\n"); - err = -ENOMEM; - goto failed; - } - data = hw->priv; - data->hw = hw; - - data->dev = device_create(hwsim_class, NULL, 0, hw, - "hwsim%d", i); - if (IS_ERR(data->dev)) { - printk(KERN_DEBUG - "mac80211_hwsim: device_create failed (%ld)\n", - PTR_ERR(data->dev)); - err = -ENOMEM; - goto failed_drvdata; - } - data->dev->driver = &mac80211_hwsim_driver.driver; - err = device_bind_driver(data->dev); - if (err != 0) { - printk(KERN_DEBUG - "mac80211_hwsim: device_bind_driver failed (%d)\n", - err); - goto failed_hw; - } - - skb_queue_head_init(&data->pending); - - SET_IEEE80211_DEV(hw, data->dev); - addr[3] = i >> 8; - addr[4] = i; - memcpy(data->addresses[0].addr, addr, ETH_ALEN); - memcpy(data->addresses[1].addr, addr, ETH_ALEN); - data->addresses[1].addr[0] |= 0x40; - hw->wiphy->n_addresses = 2; - hw->wiphy->addresses = data->addresses; - - data->channels = channels; - - if (data->channels > 1) { - 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]; - data->if_combination.num_different_channels = - data->channels; - } else { - hw->wiphy->iface_combinations = hwsim_if_comb; - hw->wiphy->n_iface_combinations = - ARRAY_SIZE(hwsim_if_comb); - } - - INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); - INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); - - hw->queues = 5; - hw->offchannel_tx_hw_queue = 4; - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT) | - BIT(NL80211_IFTYPE_P2P_DEVICE); - - hw->flags = IEEE80211_HW_MFP_CAPABLE | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_QUEUE_CONTROL | - IEEE80211_HW_SUPPORTS_HT_CCK_RATES; - 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; - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - - /* ask mac80211 to reserve space for magic */ - hw->vif_data_size = sizeof(struct hwsim_vif_priv); - hw->sta_data_size = sizeof(struct hwsim_sta_priv); - hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); - - memcpy(data->channels_2ghz, hwsim_channels_2ghz, - sizeof(hwsim_channels_2ghz)); - memcpy(data->channels_5ghz, hwsim_channels_5ghz, - sizeof(hwsim_channels_5ghz)); - memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); - - for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { - struct ieee80211_supported_band *sband = &data->bands[band]; - switch (band) { - case IEEE80211_BAND_2GHZ: - sband->channels = data->channels_2ghz; - sband->n_channels = - ARRAY_SIZE(hwsim_channels_2ghz); - sband->bitrates = data->rates; - sband->n_bitrates = ARRAY_SIZE(hwsim_rates); - break; - case IEEE80211_BAND_5GHZ: - sband->channels = data->channels_5ghz; - sband->n_channels = - ARRAY_SIZE(hwsim_channels_5ghz); - sband->bitrates = data->rates + 4; - sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; - break; - default: - continue; - } - - sband->ht_cap.ht_supported = true; - sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - sband->ht_cap.ampdu_factor = 0x3; - sband->ht_cap.ampdu_density = 0x6; - memset(&sband->ht_cap.mcs, 0, - sizeof(sband->ht_cap.mcs)); - sband->ht_cap.mcs.rx_mask[0] = 0xff; - sband->ht_cap.mcs.rx_mask[1] = 0xff; - sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - - hw->wiphy->bands[band] = sband; - - sband->vht_cap.vht_supported = true; - 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 | - IEEE80211_VHT_CAP_TXSTBC | - IEEE80211_VHT_CAP_RXSTBC_1 | - IEEE80211_VHT_CAP_RXSTBC_2 | - IEEE80211_VHT_CAP_RXSTBC_3 | - IEEE80211_VHT_CAP_RXSTBC_4 | - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; - sband->vht_cap.vht_mcs.rx_mcs_map = - cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); - sband->vht_cap.vht_mcs.tx_mcs_map = - sband->vht_cap.vht_mcs.rx_mcs_map; - } - /* By default all radios are belonging to the first group */ - data->group = 1; - mutex_init(&data->mutex); - - /* Enable frame retransmissions for lossy channels */ - hw->max_rates = 4; - hw->max_rate_tries = 11; - - err = ieee80211_register_hw(hw); - if (err < 0) { - printk(KERN_DEBUG "mac80211_hwsim: " - "ieee80211_register_hw failed (%d)\n", err); - goto failed_hw; - } - - wiphy_debug(hw->wiphy, "hwaddr %pm registered\n", - hw->wiphy->perm_addr); - - data->debugfs = debugfs_create_dir("hwsim", - hw->wiphy->debugfsdir); - debugfs_create_file("ps", 0666, data->debugfs, data, - &hwsim_fops_ps); - debugfs_create_file("group", 0666, data->debugfs, data, - &hwsim_fops_group); - if (channels == 1) - debugfs_create_file("dfs_simulate_radar", 0222, - data->debugfs, - data, &hwsim_simulate_radar); - - tasklet_hrtimer_init(&data->beacon_timer, - mac80211_hwsim_beacon, - CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); - - list_add_tail(&data->list, &hwsim_radios); + err = mac80211_hwsim_create_radio(i); + if (err) + goto out_free_radios; } hwsim_mon = alloc_netdev(0, "hwsim%d", hwsim_mon_setup); if (hwsim_mon == NULL) { err = -ENOMEM; - goto failed; + goto out_free_radios; } rtnl_lock(); - err = dev_alloc_name(hwsim_mon, hwsim_mon->name); - if (err < 0) - goto failed_mon; - + if (err < 0) { + rtnl_unlock(); + goto out_free_radios; + } err = register_netdevice(hwsim_mon); - if (err < 0) - goto failed_mon; - + if (err < 0) { + rtnl_unlock(); + goto out_free_mon; + } rtnl_unlock(); err = hwsim_init_netlink(); if (err < 0) - goto failed_nl; + goto out_free_mon; return 0; -failed_nl: - printk(KERN_DEBUG "mac80211_hwsim: failed initializing netlink\n"); - return err; - -failed_mon: - rtnl_unlock(); +out_free_mon: free_netdev(hwsim_mon); +out_free_radios: mac80211_hwsim_free(); - return err; - -failed_hw: - device_unregister(data->dev); -failed_drvdata: - ieee80211_free_hw(hw); -failed: - mac80211_hwsim_free(); -failed_unregister_driver: +out_unregister_driver: platform_driver_unregister(&mac80211_hwsim_driver); return err; } -- cgit v1.2.3 From e4afb603c0799fbca3351320180ec3c8fbeefa6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:43:11 +0100 Subject: mac80211_hwsim: refactor radio cleanup Refactor the radio cleanup into a new function to later allow deleting a single radio from the list. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 23fa6ee8eefe..cca5b3ffb22c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1623,25 +1623,29 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { static struct ieee80211_ops mac80211_hwsim_mchan_ops; -static void mac80211_hwsim_free(void) +static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) { - struct list_head tmplist, *i, *tmp; - struct mac80211_hwsim_data *data, *tmpdata; + debugfs_remove_recursive(data->debugfs); + ieee80211_unregister_hw(data->hw); + device_release_driver(data->dev); + device_unregister(data->dev); + ieee80211_free_hw(data->hw); +} - INIT_LIST_HEAD(&tmplist); +static void mac80211_hwsim_free(void) +{ + struct mac80211_hwsim_data *data; spin_lock_bh(&hwsim_radio_lock); - list_for_each_safe(i, tmp, &hwsim_radios) - list_move(i, &tmplist); - spin_unlock_bh(&hwsim_radio_lock); - - list_for_each_entry_safe(data, tmpdata, &tmplist, list) { - debugfs_remove_recursive(data->debugfs); - ieee80211_unregister_hw(data->hw); - device_release_driver(data->dev); - device_unregister(data->dev); - ieee80211_free_hw(data->hw); + while ((data = list_first_entry_or_null(&hwsim_radios, + struct mac80211_hwsim_data, + list))) { + list_del(&data->list); + spin_unlock_bh(&hwsim_radio_lock); + mac80211_hwsim_destroy_radio(data); + spin_lock_bh(&hwsim_radio_lock); } + spin_unlock_bh(&hwsim_radio_lock); class_destroy(hwsim_class); } -- cgit v1.2.3 From 8133841045b81639495dc5ca1bcab45d279661ab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:53:42 +0100 Subject: mac80211_hwsim: minimize rctbl module parameter usage Check the flag that the module parameter sets instead, so later radios can use different parameters. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index cca5b3ffb22c..59caa10a33f0 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -802,7 +802,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, if (control->sta) hwsim_check_sta_magic(control->sta); - if (rctbl) + if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE) ieee80211_get_tx_rates(txi->control.vif, control->sta, skb, txi->control.rates, ARRAY_SIZE(txi->control.rates)); @@ -909,7 +909,7 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, { u32 _pid = ACCESS_ONCE(wmediumd_portid); - if (rctbl) { + if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE) { struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); ieee80211_get_tx_rates(txi->control.vif, NULL, skb, txi->control.rates, @@ -946,7 +946,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, if (skb == NULL) return; info = IEEE80211_SKB_CB(skb); - if (rctbl) + if (hw->flags & IEEE80211_HW_SUPPORTS_RC_TABLE) ieee80211_get_tx_rates(vif, NULL, skb, info->control.rates, ARRAY_SIZE(info->control.rates)); -- cgit v1.2.3 From 2d68992b6079cd5bdfff85251c3c670ce1560d5c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 22:56:30 +0100 Subject: mac80211_hwsim: assign index from separate counter To later allow dynamic registration, assign the index for the struct device and MAC address from a new free-running counter. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 59caa10a33f0..8df3d5e8e87a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -217,6 +217,7 @@ static const struct ieee80211_rate hwsim_rates[] = { static spinlock_t hwsim_radio_lock; static struct list_head hwsim_radios; +static int hwsim_radio_idx; struct mac80211_hwsim_data { struct list_head list; @@ -2126,7 +2127,7 @@ static const struct ieee80211_iface_combination hwsim_if_comb[] = { } }; -static int __init mac80211_hwsim_create_radio(int idx) +static int __init mac80211_hwsim_create_radio(void) { int err; u8 addr[ETH_ALEN]; @@ -2134,6 +2135,11 @@ static int __init mac80211_hwsim_create_radio(int idx) struct ieee80211_hw *hw; enum ieee80211_band band; const struct ieee80211_ops *ops = &mac80211_hwsim_ops; + int idx; + + spin_lock_bh(&hwsim_radio_lock); + idx = hwsim_radio_idx++; + spin_unlock_bh(&hwsim_radio_lock); if (channels > 1) ops = &mac80211_hwsim_mchan_ops; @@ -2375,7 +2381,7 @@ static int __init init_mac80211_hwsim(void) } for (i = 0; i < radios; i++) { - err = mac80211_hwsim_create_radio(i); + err = mac80211_hwsim_create_radio(); if (err) goto out_free_radios; } -- cgit v1.2.3 From 9ddd12af103f60fc284103740c07219d888d1aee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 23:03:02 +0100 Subject: mac80211_hwsim: minor netlink cleanups Use u8 pointer instead of the struct mac_address and do some other small cleanups. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 64 +++++++++++++---------------------- 1 file changed, 23 insertions(+), 41 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 8df3d5e8e87a..ca156a5ed305 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -298,18 +298,16 @@ static struct genl_family hwsim_genl_family = { /* MAC80211_HWSIM netlink policy */ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { - [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, - .len = 6*sizeof(u8) }, - [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, - .len = 6*sizeof(u8) }, + [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, .len = IEEE80211_MAX_DATA_LEN }, [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, [HWSIM_ATTR_TX_INFO] = { .type = NLA_UNSPEC, - .len = IEEE80211_TX_MAX_RATES*sizeof( - struct hwsim_tx_rate)}, + .len = IEEE80211_TX_MAX_RATES * + sizeof(struct hwsim_tx_rate)}, [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, }; @@ -536,7 +534,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, } if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, - sizeof(struct mac_address), data->addresses[1].addr)) + ETH_ALEN, data->addresses[1].addr)) goto nla_put_failure; /* We get the skb->data */ @@ -1828,16 +1826,14 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, hwsim_fops_group_read, hwsim_fops_group_write, "%llx\n"); -static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr( - struct mac_address *addr) +static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) { struct mac80211_hwsim_data *data; bool _found = false; spin_lock_bh(&hwsim_radio_lock); list_for_each_entry(data, &hwsim_radios, list) { - if (memcmp(data->addresses[1].addr, addr, - sizeof(struct mac_address)) == 0) { + if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) { _found = true; break; } @@ -1860,27 +1856,23 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, struct hwsim_tx_rate *tx_attempts; unsigned long ret_skb_ptr; struct sk_buff *skb, *tmp; - struct mac_address *src; + const u8 *src; unsigned int hwsim_flags; - int i; bool found = false; if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || - !info->attrs[HWSIM_ATTR_FLAGS] || - !info->attrs[HWSIM_ATTR_COOKIE] || - !info->attrs[HWSIM_ATTR_TX_INFO]) + !info->attrs[HWSIM_ATTR_FLAGS] || + !info->attrs[HWSIM_ATTR_COOKIE] || + !info->attrs[HWSIM_ATTR_TX_INFO]) goto out; - src = (struct mac_address *)nla_data( - info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); + src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); - ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); data2 = get_hwsim_data_ref_from_addr(src); - - if (data2 == NULL) + if (!data2) goto out; /* look for the skb matching the cookie passed back from user */ @@ -1937,9 +1929,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, struct mac80211_hwsim_data *data2; struct ieee80211_rx_status rx_status; - struct mac_address *dst; + const u8 *dst; int frame_data_len; - char *frame_data; + void *frame_data; struct sk_buff *skb = NULL; if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || @@ -1948,27 +1940,23 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, !info->attrs[HWSIM_ATTR_SIGNAL]) goto out; - dst = (struct mac_address *)nla_data( - info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); - + dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); - frame_data = (char *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); + frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); /* Allocate new skb here */ skb = alloc_skb(frame_data_len, GFP_KERNEL); if (skb == NULL) goto err; - if (frame_data_len <= IEEE80211_MAX_DATA_LEN) { - /* Copy the data */ - memcpy(skb_put(skb, frame_data_len), frame_data, - frame_data_len); - } else + if (frame_data_len > IEEE80211_MAX_DATA_LEN) goto err; - data2 = get_hwsim_data_ref_from_addr(dst); + /* Copy the data */ + memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len); - if (data2 == NULL) + data2 = get_hwsim_data_ref_from_addr(dst); + if (!data2) goto out; /* check if radio is configured properly */ @@ -1976,7 +1964,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, if (data2->idle || !data2->started) goto out; - /*A frame is received from user space*/ + /* A frame is received from user space */ memset(&rx_status, 0, sizeof(rx_status)); rx_status.freq = data2->channel->center_freq; rx_status.band = data2->channel->band; @@ -1998,18 +1986,12 @@ out: static int hwsim_register_received_nl(struct sk_buff *skb_2, struct genl_info *info) { - if (info == NULL) - goto out; - wmediumd_portid = info->snd_portid; printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " "switching to wmediumd mode with pid %d\n", info->snd_portid); return 0; -out: - printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); - return -EINVAL; } /* Generic Netlink operations array */ -- cgit v1.2.3 From de0421d53bfb5f7783e5228f8cf49f2ae7140d54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 23:12:12 +0100 Subject: mac80211_hwsim: shuffle code to prepare for dynamic radios This will make the next patch, adding support for netlink, smaller and more readable. The code is not modified here. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 832 +++++++++++++++++----------------- 1 file changed, 416 insertions(+), 416 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index ca156a5ed305..1c51c33c385f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -215,10 +215,53 @@ static const struct ieee80211_rate hwsim_rates[] = { { .bitrate = 540 } }; +static const struct ieee80211_iface_limit hwsim_if_limits[] = { + { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, +}; + +static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { + { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, +}; + +static const struct ieee80211_iface_combination hwsim_if_comb[] = { + { + .limits = hwsim_if_limits, + .n_limits = ARRAY_SIZE(hwsim_if_limits), + .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 spinlock_t hwsim_radio_lock; static struct list_head hwsim_radios; static int hwsim_radio_idx; +static struct platform_driver mac80211_hwsim_driver = { + .driver = { + .name = "mac80211_hwsim", + .owner = THIS_MODULE, + }, +}; + struct mac80211_hwsim_data { struct list_head list; struct ieee80211_hw *hw; @@ -311,6 +354,161 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, }; +static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_channel *chan); + +/* sysfs attributes */ +static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + struct sk_buff *skb; + struct ieee80211_pspoll *pspoll; + + if (!vp->assoc) + return; + + wiphy_debug(data->hw->wiphy, + "%s: send PS-Poll to %pM for aid %d\n", + __func__, vp->bssid, vp->aid); + + skb = dev_alloc_skb(sizeof(*pspoll)); + if (!skb) + return; + pspoll = (void *) skb_put(skb, sizeof(*pspoll)); + pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_PSPOLL | + IEEE80211_FCTL_PM); + pspoll->aid = cpu_to_le16(0xc000 | vp->aid); + memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); + memcpy(pspoll->ta, mac, ETH_ALEN); + + rcu_read_lock(); + mac80211_hwsim_tx_frame(data->hw, skb, + rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_read_unlock(); +} + +static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, + struct ieee80211_vif *vif, int ps) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + + if (!vp->assoc) + return; + + wiphy_debug(data->hw->wiphy, + "%s: send data::nullfunc to %pM ps=%d\n", + __func__, vp->bssid, ps); + + skb = dev_alloc_skb(sizeof(*hdr)); + if (!skb) + return; + hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + (ps ? IEEE80211_FCTL_PM : 0)); + hdr->duration_id = cpu_to_le16(0); + memcpy(hdr->addr1, vp->bssid, ETH_ALEN); + memcpy(hdr->addr2, mac, ETH_ALEN); + memcpy(hdr->addr3, vp->bssid, ETH_ALEN); + + rcu_read_lock(); + mac80211_hwsim_tx_frame(data->hw, skb, + rcu_dereference(vif->chanctx_conf)->def.chan); + rcu_read_unlock(); +} + + +static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 1); +} + +static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 0); +} + +static int hwsim_fops_ps_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->ps; + return 0; +} + +static int hwsim_fops_ps_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + enum ps_mode old_ps; + + if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && + val != PS_MANUAL_POLL) + return -EINVAL; + + old_ps = data->ps; + data->ps = val; + + if (val == PS_MANUAL_POLL) { + ieee80211_iterate_active_interfaces(data->hw, + IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_ps_poll, data); + data->ps_poll_pending = true; + } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_ps, + data); + } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + IEEE80211_IFACE_ITER_NORMAL, + hwsim_send_nullfunc_no_ps, + data); + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, + "%llu\n"); + +static int hwsim_write_simulate_radar(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + + ieee80211_radar_detected(data->hw); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, + hwsim_write_simulate_radar, "%llu\n"); + +static int hwsim_fops_group_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->group; + return 0; +} + +static int hwsim_fops_group_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + data->group = val; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, + hwsim_fops_group_read, hwsim_fops_group_write, + "%llx\n"); + static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1283,8 +1481,6 @@ static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 }, }; -static int hwsim_fops_ps_write(void *dat, u64 val); - static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len) @@ -1622,210 +1818,265 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { static struct ieee80211_ops mac80211_hwsim_mchan_ops; -static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) -{ - debugfs_remove_recursive(data->debugfs); - ieee80211_unregister_hw(data->hw); - device_release_driver(data->dev); - device_unregister(data->dev); - ieee80211_free_hw(data->hw); -} - -static void mac80211_hwsim_free(void) +static int __init mac80211_hwsim_create_radio(void) { + int err; + u8 addr[ETH_ALEN]; struct mac80211_hwsim_data *data; + struct ieee80211_hw *hw; + enum ieee80211_band band; + const struct ieee80211_ops *ops = &mac80211_hwsim_ops; + int idx; spin_lock_bh(&hwsim_radio_lock); - while ((data = list_first_entry_or_null(&hwsim_radios, - struct mac80211_hwsim_data, - list))) { - list_del(&data->list); - spin_unlock_bh(&hwsim_radio_lock); - mac80211_hwsim_destroy_radio(data); - spin_lock_bh(&hwsim_radio_lock); - } + idx = hwsim_radio_idx++; spin_unlock_bh(&hwsim_radio_lock); - class_destroy(hwsim_class); -} - -static struct platform_driver mac80211_hwsim_driver = { - .driver = { - .name = "mac80211_hwsim", - .owner = THIS_MODULE, - }, -}; -static const struct net_device_ops hwsim_netdev_ops = { - .ndo_start_xmit = hwsim_mon_xmit, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; + if (channels > 1) + ops = &mac80211_hwsim_mchan_ops; + hw = ieee80211_alloc_hw(sizeof(*data), ops); + if (!hw) { + printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); + err = -ENOMEM; + goto failed; + } + data = hw->priv; + data->hw = hw; -static void hwsim_mon_setup(struct net_device *dev) -{ - dev->netdev_ops = &hwsim_netdev_ops; - dev->destructor = free_netdev; - ether_setup(dev); - dev->tx_queue_len = 0; - dev->type = ARPHRD_IEEE80211_RADIOTAP; - memset(dev->dev_addr, 0, ETH_ALEN); - dev->dev_addr[0] = 0x12; -} + data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); + if (IS_ERR(data->dev)) { + printk(KERN_DEBUG + "mac80211_hwsim: device_create failed (%ld)\n", + PTR_ERR(data->dev)); + err = -ENOMEM; + goto failed_drvdata; + } + data->dev->driver = &mac80211_hwsim_driver.driver; + err = device_bind_driver(data->dev); + if (err != 0) { + printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", + err); + goto failed_hw; + } + skb_queue_head_init(&data->pending); -static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) -{ - struct mac80211_hwsim_data *data = dat; - struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - struct sk_buff *skb; - struct ieee80211_pspoll *pspoll; + SET_IEEE80211_DEV(hw, data->dev); + memset(addr, 0, ETH_ALEN); + addr[0] = 0x02; + addr[3] = idx >> 8; + addr[4] = idx; + memcpy(data->addresses[0].addr, addr, ETH_ALEN); + memcpy(data->addresses[1].addr, addr, ETH_ALEN); + data->addresses[1].addr[0] |= 0x40; + hw->wiphy->n_addresses = 2; + hw->wiphy->addresses = data->addresses; - if (!vp->assoc) - return; + data->channels = channels; - wiphy_debug(data->hw->wiphy, - "%s: send PS-Poll to %pM for aid %d\n", - __func__, vp->bssid, vp->aid); + if (data->channels > 1) { + 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]; + data->if_combination.num_different_channels = data->channels; + } else { + hw->wiphy->iface_combinations = hwsim_if_comb; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); + } - skb = dev_alloc_skb(sizeof(*pspoll)); - if (!skb) - return; - pspoll = (void *) skb_put(skb, sizeof(*pspoll)); - pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_PSPOLL | - IEEE80211_FCTL_PM); - pspoll->aid = cpu_to_le16(0xc000 | vp->aid); - memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); - memcpy(pspoll->ta, mac, ETH_ALEN); + INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); + INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); - rcu_read_lock(); - mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); - rcu_read_unlock(); -} + hw->queues = 5; + hw->offchannel_tx_hw_queue = 4; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_P2P_DEVICE); -static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, - struct ieee80211_vif *vif, int ps) -{ - struct hwsim_vif_priv *vp = (void *)vif->drv_priv; - struct sk_buff *skb; - struct ieee80211_hdr *hdr; + hw->flags = IEEE80211_HW_MFP_CAPABLE | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_SUPPORTS_STATIC_SMPS | + IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_WANT_MONITOR_VIF | + IEEE80211_HW_QUEUE_CONTROL | + IEEE80211_HW_SUPPORTS_HT_CCK_RATES; + if (rctbl) + hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE; - if (!vp->assoc) - return; + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_AP_UAPSD; + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - wiphy_debug(data->hw->wiphy, - "%s: send data::nullfunc to %pM ps=%d\n", - __func__, vp->bssid, ps); + /* ask mac80211 to reserve space for magic */ + hw->vif_data_size = sizeof(struct hwsim_vif_priv); + hw->sta_data_size = sizeof(struct hwsim_sta_priv); + hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); - skb = dev_alloc_skb(sizeof(*hdr)); - if (!skb) - return; - hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | - (ps ? IEEE80211_FCTL_PM : 0)); - hdr->duration_id = cpu_to_le16(0); - memcpy(hdr->addr1, vp->bssid, ETH_ALEN); - memcpy(hdr->addr2, mac, ETH_ALEN); - memcpy(hdr->addr3, vp->bssid, ETH_ALEN); + memcpy(data->channels_2ghz, hwsim_channels_2ghz, + sizeof(hwsim_channels_2ghz)); + memcpy(data->channels_5ghz, hwsim_channels_5ghz, + sizeof(hwsim_channels_5ghz)); + memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); - rcu_read_lock(); - mac80211_hwsim_tx_frame(data->hw, skb, - rcu_dereference(vif->chanctx_conf)->def.chan); - rcu_read_unlock(); -} + for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband = &data->bands[band]; + switch (band) { + case IEEE80211_BAND_2GHZ: + sband->channels = data->channels_2ghz; + sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); + sband->bitrates = data->rates; + sband->n_bitrates = ARRAY_SIZE(hwsim_rates); + break; + case IEEE80211_BAND_5GHZ: + sband->channels = data->channels_5ghz; + sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); + sband->bitrates = data->rates + 4; + sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; + break; + default: + continue; + } + sband->ht_cap.ht_supported = true; + sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + sband->ht_cap.ampdu_factor = 0x3; + sband->ht_cap.ampdu_density = 0x6; + memset(&sband->ht_cap.mcs, 0, + sizeof(sband->ht_cap.mcs)); + sband->ht_cap.mcs.rx_mask[0] = 0xff; + sband->ht_cap.mcs.rx_mask[1] = 0xff; + sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; -static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mac80211_hwsim_data *data = dat; - hwsim_send_nullfunc(data, mac, vif, 1); -} + hw->wiphy->bands[band] = sband; + sband->vht_cap.vht_supported = true; + 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 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_RXSTBC_2 | + IEEE80211_VHT_CAP_RXSTBC_3 | + IEEE80211_VHT_CAP_RXSTBC_4 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + sband->vht_cap.vht_mcs.rx_mcs_map = + cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | + IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | + IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); + sband->vht_cap.vht_mcs.tx_mcs_map = + sband->vht_cap.vht_mcs.rx_mcs_map; + } -static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mac80211_hwsim_data *data = dat; - hwsim_send_nullfunc(data, mac, vif, 0); -} + /* By default all radios belong to the first group */ + data->group = 1; + mutex_init(&data->mutex); + /* Enable frame retransmissions for lossy channels */ + hw->max_rates = 4; + hw->max_rate_tries = 11; -static int hwsim_fops_ps_read(void *dat, u64 *val) -{ - struct mac80211_hwsim_data *data = dat; - *val = data->ps; - return 0; -} + err = ieee80211_register_hw(hw); + if (err < 0) { + printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", + err); + goto failed_hw; + } -static int hwsim_fops_ps_write(void *dat, u64 val) -{ - struct mac80211_hwsim_data *data = dat; - enum ps_mode old_ps; + wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); - if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && - val != PS_MANUAL_POLL) - return -EINVAL; + data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); + 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) + debugfs_create_file("dfs_simulate_radar", 0222, + data->debugfs, + data, &hwsim_simulate_radar); - old_ps = data->ps; - data->ps = val; + tasklet_hrtimer_init(&data->beacon_timer, + mac80211_hwsim_beacon, + CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); - if (val == PS_MANUAL_POLL) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_ps_poll, data); - data->ps_poll_pending = true; - } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_ps, - data); - } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { - ieee80211_iterate_active_interfaces(data->hw, - IEEE80211_IFACE_ITER_NORMAL, - hwsim_send_nullfunc_no_ps, - data); - } + spin_lock_bh(&hwsim_radio_lock); + list_add_tail(&data->list, &hwsim_radios); + spin_unlock_bh(&hwsim_radio_lock); return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, - "%llu\n"); +failed_hw: + device_unregister(data->dev); +failed_drvdata: + ieee80211_free_hw(hw); +failed: + return err; +} -static int hwsim_write_simulate_radar(void *dat, u64 val) +static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data) { - struct mac80211_hwsim_data *data = dat; - - ieee80211_radar_detected(data->hw); - - return 0; + debugfs_remove_recursive(data->debugfs); + ieee80211_unregister_hw(data->hw); + device_release_driver(data->dev); + device_unregister(data->dev); + ieee80211_free_hw(data->hw); } -DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, - hwsim_write_simulate_radar, "%llu\n"); - -static int hwsim_fops_group_read(void *dat, u64 *val) +static void mac80211_hwsim_free(void) { - struct mac80211_hwsim_data *data = dat; - *val = data->group; - return 0; + struct mac80211_hwsim_data *data; + + spin_lock_bh(&hwsim_radio_lock); + while ((data = list_first_entry_or_null(&hwsim_radios, + struct mac80211_hwsim_data, + list))) { + list_del(&data->list); + spin_unlock_bh(&hwsim_radio_lock); + mac80211_hwsim_destroy_radio(data); + spin_lock_bh(&hwsim_radio_lock); + } + spin_unlock_bh(&hwsim_radio_lock); + class_destroy(hwsim_class); } -static int hwsim_fops_group_write(void *dat, u64 val) +static const struct net_device_ops hwsim_netdev_ops = { + .ndo_start_xmit = hwsim_mon_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +static void hwsim_mon_setup(struct net_device *dev) { - struct mac80211_hwsim_data *data = dat; - data->group = val; - return 0; + dev->netdev_ops = &hwsim_netdev_ops; + dev->destructor = free_netdev; + ether_setup(dev); + dev->tx_queue_len = 0; + dev->type = ARPHRD_IEEE80211_RADIOTAP; + memset(dev->dev_addr, 0, ETH_ALEN); + dev->dev_addr[0] = 0x12; } -DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, - hwsim_fops_group_read, hwsim_fops_group_write, - "%llx\n"); - static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr) { struct mac80211_hwsim_data *data; @@ -2073,257 +2324,6 @@ static void hwsim_exit_netlink(void) genl_unregister_family(&hwsim_genl_family); } -static const struct ieee80211_iface_limit hwsim_if_limits[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, - { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_GO) }, - { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, -}; - -static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = { - { .max = 8, .types = BIT(NL80211_IFTYPE_AP) }, -}; - -static const struct ieee80211_iface_combination hwsim_if_comb[] = { - { - .limits = hwsim_if_limits, - .n_limits = ARRAY_SIZE(hwsim_if_limits), - .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 int __init mac80211_hwsim_create_radio(void) -{ - int err; - u8 addr[ETH_ALEN]; - struct mac80211_hwsim_data *data; - struct ieee80211_hw *hw; - enum ieee80211_band band; - const struct ieee80211_ops *ops = &mac80211_hwsim_ops; - int idx; - - spin_lock_bh(&hwsim_radio_lock); - idx = hwsim_radio_idx++; - spin_unlock_bh(&hwsim_radio_lock); - - if (channels > 1) - ops = &mac80211_hwsim_mchan_ops; - hw = ieee80211_alloc_hw(sizeof(*data), ops); - if (!hw) { - printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n"); - err = -ENOMEM; - goto failed; - } - data = hw->priv; - data->hw = hw; - - data->dev = device_create(hwsim_class, NULL, 0, hw, "hwsim%d", idx); - if (IS_ERR(data->dev)) { - printk(KERN_DEBUG - "mac80211_hwsim: device_create failed (%ld)\n", - PTR_ERR(data->dev)); - err = -ENOMEM; - goto failed_drvdata; - } - data->dev->driver = &mac80211_hwsim_driver.driver; - err = device_bind_driver(data->dev); - if (err != 0) { - printk(KERN_DEBUG "mac80211_hwsim: device_bind_driver failed (%d)\n", - err); - goto failed_hw; - } - - skb_queue_head_init(&data->pending); - - SET_IEEE80211_DEV(hw, data->dev); - memset(addr, 0, ETH_ALEN); - addr[0] = 0x02; - addr[3] = idx >> 8; - addr[4] = idx; - memcpy(data->addresses[0].addr, addr, ETH_ALEN); - memcpy(data->addresses[1].addr, addr, ETH_ALEN); - data->addresses[1].addr[0] |= 0x40; - hw->wiphy->n_addresses = 2; - hw->wiphy->addresses = data->addresses; - - data->channels = channels; - - if (data->channels > 1) { - 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]; - data->if_combination.num_different_channels = data->channels; - } else { - hw->wiphy->iface_combinations = hwsim_if_comb; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb); - } - - INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); - INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); - - hw->queues = 5; - hw->offchannel_tx_hw_queue = 4; - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT) | - BIT(NL80211_IFTYPE_P2P_DEVICE); - - hw->flags = IEEE80211_HW_MFP_CAPABLE | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_STATIC_SMPS | - IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_QUEUE_CONTROL | - IEEE80211_HW_SUPPORTS_HT_CCK_RATES; - 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; - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - - /* ask mac80211 to reserve space for magic */ - hw->vif_data_size = sizeof(struct hwsim_vif_priv); - hw->sta_data_size = sizeof(struct hwsim_sta_priv); - hw->chanctx_data_size = sizeof(struct hwsim_chanctx_priv); - - memcpy(data->channels_2ghz, hwsim_channels_2ghz, - sizeof(hwsim_channels_2ghz)); - memcpy(data->channels_5ghz, hwsim_channels_5ghz, - sizeof(hwsim_channels_5ghz)); - memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); - - for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { - struct ieee80211_supported_band *sband = &data->bands[band]; - switch (band) { - case IEEE80211_BAND_2GHZ: - sband->channels = data->channels_2ghz; - sband->n_channels = ARRAY_SIZE(hwsim_channels_2ghz); - sband->bitrates = data->rates; - sband->n_bitrates = ARRAY_SIZE(hwsim_rates); - break; - case IEEE80211_BAND_5GHZ: - sband->channels = data->channels_5ghz; - sband->n_channels = ARRAY_SIZE(hwsim_channels_5ghz); - sband->bitrates = data->rates + 4; - sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; - break; - default: - continue; - } - - sband->ht_cap.ht_supported = true; - sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_GRN_FLD | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - sband->ht_cap.ampdu_factor = 0x3; - sband->ht_cap.ampdu_density = 0x6; - memset(&sband->ht_cap.mcs, 0, - sizeof(sband->ht_cap.mcs)); - sband->ht_cap.mcs.rx_mask[0] = 0xff; - sband->ht_cap.mcs.rx_mask[1] = 0xff; - sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - - hw->wiphy->bands[band] = sband; - - sband->vht_cap.vht_supported = true; - 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 | - IEEE80211_VHT_CAP_TXSTBC | - IEEE80211_VHT_CAP_RXSTBC_1 | - IEEE80211_VHT_CAP_RXSTBC_2 | - IEEE80211_VHT_CAP_RXSTBC_3 | - IEEE80211_VHT_CAP_RXSTBC_4 | - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; - sband->vht_cap.vht_mcs.rx_mcs_map = - cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | - IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | - IEEE80211_VHT_MCS_SUPPORT_0_8 << 14); - sband->vht_cap.vht_mcs.tx_mcs_map = - sband->vht_cap.vht_mcs.rx_mcs_map; - } - - /* By default all radios belong to the first group */ - data->group = 1; - mutex_init(&data->mutex); - - /* Enable frame retransmissions for lossy channels */ - hw->max_rates = 4; - hw->max_rate_tries = 11; - - err = ieee80211_register_hw(hw); - if (err < 0) { - printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", - err); - goto failed_hw; - } - - wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); - - data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); - 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) - debugfs_create_file("dfs_simulate_radar", 0222, - data->debugfs, - data, &hwsim_simulate_radar); - - tasklet_hrtimer_init(&data->beacon_timer, - mac80211_hwsim_beacon, - CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS); - - spin_lock_bh(&hwsim_radio_lock); - list_add_tail(&data->list, &hwsim_radios); - spin_unlock_bh(&hwsim_radio_lock); - - return 0; - -failed_hw: - device_unregister(data->dev); -failed_drvdata: - ieee80211_free_hw(hw); -failed: - return err; -} - static int __init init_mac80211_hwsim(void) { int i, err; -- cgit v1.2.3 From 85ca8fc74671def6041fb12c0a7d3423da56ffd3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jan 2014 23:21:34 +0100 Subject: mac80211_hwsim: verify wmediumd socket There can't be two wmediumd instances controlling hwsim, so reject registration from a second one and verify in the commands that it's the correct instance calling. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1c51c33c385f..4ee88a9b095d 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2112,6 +2112,9 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, int i; bool found = false; + if (info->snd_portid != wmediumd_portid) + return -EINVAL; + if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || !info->attrs[HWSIM_ATTR_FLAGS] || !info->attrs[HWSIM_ATTR_COOKIE] || @@ -2185,6 +2188,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, void *frame_data; struct sk_buff *skb = NULL; + if (info->snd_portid != wmediumd_portid) + return -EINVAL; + if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || !info->attrs[HWSIM_ATTR_FRAME] || !info->attrs[HWSIM_ATTR_RX_RATE] || @@ -2237,6 +2243,9 @@ out: static int hwsim_register_received_nl(struct sk_buff *skb_2, struct genl_info *info) { + if (wmediumd_portid) + return -EBUSY; + wmediumd_portid = info->snd_portid; printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " -- cgit v1.2.3 From c5ac08548b53c3292aa3cbd02de6ae99ca7271e6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jan 2014 23:28:08 +0100 Subject: mac80211_hwsim: register netlink even with multi-channel Reject wmediumd registrations when any devices have multi-channel capability, but register the generic netlink family unconditionally to make it possible to add new commands that shouldn't depend on the number of (default) channels. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4ee88a9b095d..5bad3d4ccdba 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2243,6 +2243,22 @@ out: static int hwsim_register_received_nl(struct sk_buff *skb_2, struct genl_info *info) { + struct mac80211_hwsim_data *data; + int chans = 1; + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_entry(data, &hwsim_radios, list) + chans = max(chans, data->channels); + spin_unlock_bh(&hwsim_radio_lock); + + /* In the future we should revise the userspace API and allow it + * to set a flag that it does support multi-channel, then we can + * let this pass conditionally on the flag. + * For current userspace, prohibit it since it won't work right. + */ + if (chans > 1) + return -EOPNOTSUPP; + if (wmediumd_portid) return -EBUSY; @@ -2300,10 +2316,6 @@ static int hwsim_init_netlink(void) { int rc; - /* userspace test API hasn't been adjusted for multi-channel */ - if (channels > 1) - return 0; - printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops); @@ -2323,10 +2335,6 @@ failure: static void hwsim_exit_netlink(void) { - /* userspace test API hasn't been adjusted for multi-channel */ - if (channels > 1) - return; - /* unregister the notifier */ netlink_unregister_notifier(&hwsim_netlink_notifier); /* unregister the family */ -- cgit v1.2.3 From bc7910989601fbde02b3dd485d595a614d21ef1e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 6 Jan 2014 23:29:20 +0100 Subject: mac80211_hwsim: allow creating/destroying radios on the fly Add new commands to the hwsim generic netlink family to allow creating and destroying radios on the fly. The number of channels a radio supports can be specified when it's created, if it isn't the module parameter will be used as default. This should be extended in the future to allow other parameters to be specified, e.g. * list of channels * interface combinations, particularly P2P_DEVICE support * regtest * and pretty much all other hardware capabilities Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 60 +++++++++++++++++++++++++++++++---- drivers/net/wireless/mac80211_hwsim.h | 11 +++++++ 2 files changed, 65 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 5bad3d4ccdba..056dae73b25c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -273,7 +273,7 @@ struct mac80211_hwsim_data { struct ieee80211_iface_combination if_combination; struct mac_address addresses[2]; - int channels; + int channels, idx; struct ieee80211_channel *tmp_chan; struct delayed_work roc_done; @@ -352,6 +352,8 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { .len = IEEE80211_TX_MAX_RATES * sizeof(struct hwsim_tx_rate)}, [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, + [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 }, + [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 }, }; static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, @@ -1818,7 +1820,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { static struct ieee80211_ops mac80211_hwsim_mchan_ops; -static int __init mac80211_hwsim_create_radio(void) +static int mac80211_hwsim_create_radio(int channels) { int err; u8 addr[ETH_ALEN]; @@ -1873,6 +1875,7 @@ static int __init mac80211_hwsim_create_radio(void) hw->wiphy->addresses = data->addresses; data->channels = channels; + data->idx = idx; if (data->channels > 1) { hw->wiphy->max_scan_ssids = 255; @@ -2023,7 +2026,7 @@ static int __init mac80211_hwsim_create_radio(void) list_add_tail(&data->list, &hwsim_radios); spin_unlock_bh(&hwsim_radio_lock); - return 0; + return idx; failed_hw: device_unregister(data->dev); @@ -2270,6 +2273,39 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2, return 0; } +static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) +{ + unsigned int chans = channels; + + if (info->attrs[HWSIM_ATTR_CHANNELS]) + chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); + + return mac80211_hwsim_create_radio(chans); +} + +static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) +{ + struct mac80211_hwsim_data *data; + int idx; + + if (!info->attrs[HWSIM_ATTR_RADIO_ID]) + return -EINVAL; + idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]); + + spin_lock_bh(&hwsim_radio_lock); + list_for_each_entry(data, &hwsim_radios, list) { + if (data->idx != idx) + continue; + list_del(&data->list); + spin_unlock_bh(&hwsim_radio_lock); + mac80211_hwsim_destroy_radio(data); + return 0; + } + spin_unlock_bh(&hwsim_radio_lock); + + return -ENODEV; +} + /* Generic Netlink operations array */ static const struct genl_ops hwsim_ops[] = { { @@ -2288,6 +2324,18 @@ static const struct genl_ops hwsim_ops[] = { .policy = hwsim_genl_policy, .doit = hwsim_tx_info_frame_received_nl, }, + { + .cmd = HWSIM_CMD_CREATE_RADIO, + .policy = hwsim_genl_policy, + .doit = hwsim_create_radio_nl, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = HWSIM_CMD_DESTROY_RADIO, + .policy = hwsim_genl_policy, + .doit = hwsim_destroy_radio_nl, + .flags = GENL_ADMIN_PERM, + }, }; static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, @@ -2345,7 +2393,7 @@ static int __init init_mac80211_hwsim(void) { int i, err; - if (radios < 1 || radios > 100) + if (radios < 0 || radios > 100) return -EINVAL; if (channels < 1) @@ -2380,8 +2428,8 @@ static int __init init_mac80211_hwsim(void) } for (i = 0; i < radios; i++) { - err = mac80211_hwsim_create_radio(); - if (err) + err = mac80211_hwsim_create_radio(channels); + if (err < 0) goto out_free_radios; } diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index afaad5a443b6..fb9920a99396 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -65,6 +65,9 @@ enum hwsim_tx_control_flags { * kernel, uses: * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE + * @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters, + * returns the radio ID (>= 0) or negative on errors + * @HWSIM_CMD_DESTROY_RADIO: destroy a radio * @__HWSIM_CMD_MAX: enum limit */ enum { @@ -72,6 +75,8 @@ enum { HWSIM_CMD_REGISTER, HWSIM_CMD_FRAME, HWSIM_CMD_TX_INFO_FRAME, + HWSIM_CMD_CREATE_RADIO, + HWSIM_CMD_DESTROY_RADIO, __HWSIM_CMD_MAX, }; #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) @@ -94,6 +99,10 @@ enum { space * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame + * @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO + * command giving the number of channels supported by the new radio + * @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO + * only to destroy a radio * @__HWSIM_ATTR_MAX: enum limit */ @@ -108,6 +117,8 @@ enum { HWSIM_ATTR_SIGNAL, HWSIM_ATTR_TX_INFO, HWSIM_ATTR_COOKIE, + HWSIM_ATTR_CHANNELS, + HWSIM_ATTR_RADIO_ID, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) -- cgit v1.2.3 From 26b0e411d37a2ca5992d02884dc3fa4e1907e598 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jan 2014 13:37:38 +0100 Subject: mac80211_hwsim: restore regulatory testing functionality Restore the original regulatory testing functionality and also make it more flexible by allowing the parameters to be specified when creating a dynamic radio. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 218 +++++++++++++++++++++++++++++++++- drivers/net/wireless/mac80211_hwsim.h | 7 ++ 2 files changed, 222 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/mac80211_hwsim.c') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 056dae73b25c..dc7f72e3a4e7 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -57,6 +57,117 @@ static bool rctbl = false; module_param(rctbl, bool, 0444); MODULE_PARM_DESC(rctbl, "Handle rate control table"); +/** + * enum hwsim_regtest - the type of regulatory tests we offer + * + * These are the different values you can use for the regtest + * module parameter. This is useful to help test world roaming + * and the driver regulatory_hint() call and combinations of these. + * If you want to do specific alpha2 regulatory domain tests simply + * use the userspace regulatory request as that will be respected as + * well without the need of this module parameter. This is designed + * only for testing the driver regulatory request, world roaming + * and all possible combinations. + * + * @HWSIM_REGTEST_DISABLED: No regulatory tests are performed, + * this is the default value. + * @HWSIM_REGTEST_DRIVER_REG_FOLLOW: Used for testing the driver regulatory + * hint, only one driver regulatory hint will be sent as such the + * secondary radios are expected to follow. + * @HWSIM_REGTEST_DRIVER_REG_ALL: Used for testing the driver regulatory + * request with all radios reporting the same regulatory domain. + * @HWSIM_REGTEST_DIFF_COUNTRY: Used for testing the drivers calling + * different regulatory domains requests. Expected behaviour is for + * an intersection to occur but each device will still use their + * respective regulatory requested domains. Subsequent radios will + * use the resulting intersection. + * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We accomplish + * this by using a custom beacon-capable regulatory domain for the first + * radio. All other device world roam. + * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory + * domain requests. All radios will adhere to this custom world regulatory + * domain. + * @HWSIM_REGTEST_CUSTOM_WORLD_2: Used for testing 2 custom world regulatory + * domain requests. The first radio will adhere to the first custom world + * regulatory domain, the second one to the second custom world regulatory + * domain. All other devices will world roam. + * @HWSIM_REGTEST_STRICT_FOLLOW_: Used for testing strict regulatory domain + * settings, only the first radio will send a regulatory domain request + * and use strict settings. The rest of the radios are expected to follow. + * @HWSIM_REGTEST_STRICT_ALL: Used for testing strict regulatory domain + * settings. All radios will adhere to this. + * @HWSIM_REGTEST_STRICT_AND_DRIVER_REG: Used for testing strict regulatory + * domain settings, combined with secondary driver regulatory domain + * settings. The first radio will get a strict regulatory domain setting + * using the first driver regulatory request and the second radio will use + * non-strict settings using the second driver regulatory request. All + * other devices should follow the intersection created between the + * first two. + * @HWSIM_REGTEST_ALL: Used for testing every possible mix. You will need + * at least 6 radios for a complete test. We will test in this order: + * 1 - driver custom world regulatory domain + * 2 - second custom world regulatory domain + * 3 - first driver regulatory domain request + * 4 - second driver regulatory domain request + * 5 - strict regulatory domain settings using the third driver regulatory + * domain request + * 6 and on - should follow the intersection of the 3rd, 4rth and 5th radio + * regulatory requests. + */ +enum hwsim_regtest { + HWSIM_REGTEST_DISABLED = 0, + HWSIM_REGTEST_DRIVER_REG_FOLLOW = 1, + HWSIM_REGTEST_DRIVER_REG_ALL = 2, + HWSIM_REGTEST_DIFF_COUNTRY = 3, + HWSIM_REGTEST_WORLD_ROAM = 4, + HWSIM_REGTEST_CUSTOM_WORLD = 5, + HWSIM_REGTEST_CUSTOM_WORLD_2 = 6, + HWSIM_REGTEST_STRICT_FOLLOW = 7, + HWSIM_REGTEST_STRICT_ALL = 8, + HWSIM_REGTEST_STRICT_AND_DRIVER_REG = 9, + HWSIM_REGTEST_ALL = 10, +}; + +/* Set to one of the HWSIM_REGTEST_* values above */ +static int regtest = HWSIM_REGTEST_DISABLED; +module_param(regtest, int, 0444); +MODULE_PARM_DESC(regtest, "The type of regulatory test we want to run"); + +static const char *hwsim_alpha2s[] = { + "FI", + "AL", + "US", + "DE", + "JP", + "AL", +}; + +static const struct ieee80211_regdomain hwsim_world_regdom_custom_01 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), + REG_RULE(2484-10, 2484+10, 40, 0, 20, 0), + REG_RULE(5150-10, 5240+10, 40, 0, 30, 0), + REG_RULE(5745-10, 5825+10, 40, 0, 30, 0), + } +}; + +static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { + .n_reg_rules = 2, + .alpha2 = "99", + .reg_rules = { + REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), + REG_RULE(5725-10, 5850+10, 40, 0, 30, + NL80211_RRF_NO_IR), + } +}; + +static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = { + &hwsim_world_regdom_custom_01, + &hwsim_world_regdom_custom_02, +}; + struct hwsim_vif_priv { u32 magic; u8 bssid[ETH_ALEN]; @@ -354,6 +465,9 @@ static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, [HWSIM_ATTR_CHANNELS] = { .type = NLA_U32 }, [HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 }, + [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 }, }; static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, @@ -1820,7 +1934,9 @@ static const struct ieee80211_ops mac80211_hwsim_ops = { static struct ieee80211_ops mac80211_hwsim_mchan_ops; -static int mac80211_hwsim_create_radio(int channels) +static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2, + const struct ieee80211_regdomain *regd, + bool reg_strict) { int err; u8 addr[ETH_ALEN]; @@ -2000,6 +2116,15 @@ static int mac80211_hwsim_create_radio(int channels) hw->max_rates = 4; hw->max_rate_tries = 11; + if (reg_strict) + hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG; + if (regd) { + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + wiphy_apply_custom_regulatory(hw->wiphy, regd); + /* give the regulatory workqueue a chance to run */ + schedule_timeout_interruptible(1); + } + err = ieee80211_register_hw(hw); if (err < 0) { printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", @@ -2009,6 +2134,9 @@ static int mac80211_hwsim_create_radio(int channels) wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr); + if (reg_alpha2) + regulatory_hint(hw->wiphy, reg_alpha2); + data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir); debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps); debugfs_create_file("group", 0666, data->debugfs, data, @@ -2276,11 +2404,25 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2, static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info) { unsigned int chans = channels; + const char *alpha2 = NULL; + const struct ieee80211_regdomain *regd = NULL; + bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; if (info->attrs[HWSIM_ATTR_CHANNELS]) chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); - return mac80211_hwsim_create_radio(chans); + if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]) + alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]); + + if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { + u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); + + if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) + return -EINVAL; + regd = hwsim_world_regdom_custom[idx]; + } + + return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict); } static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info) @@ -2428,7 +2570,77 @@ static int __init init_mac80211_hwsim(void) } for (i = 0; i < radios; i++) { - err = mac80211_hwsim_create_radio(channels); + const char *reg_alpha2 = NULL; + const struct ieee80211_regdomain *regd = NULL; + bool reg_strict = false; + + switch (regtest) { + case HWSIM_REGTEST_DIFF_COUNTRY: + if (i < ARRAY_SIZE(hwsim_alpha2s)) + reg_alpha2 = hwsim_alpha2s[i]; + break; + case HWSIM_REGTEST_DRIVER_REG_FOLLOW: + if (!i) + reg_alpha2 = hwsim_alpha2s[0]; + break; + case HWSIM_REGTEST_STRICT_ALL: + reg_strict = true; + case HWSIM_REGTEST_DRIVER_REG_ALL: + reg_alpha2 = hwsim_alpha2s[0]; + break; + case HWSIM_REGTEST_WORLD_ROAM: + if (i == 0) + regd = &hwsim_world_regdom_custom_01; + break; + case HWSIM_REGTEST_CUSTOM_WORLD: + regd = &hwsim_world_regdom_custom_01; + break; + case HWSIM_REGTEST_CUSTOM_WORLD_2: + if (i == 0) + regd = &hwsim_world_regdom_custom_01; + else if (i == 1) + regd = &hwsim_world_regdom_custom_02; + break; + case HWSIM_REGTEST_STRICT_FOLLOW: + if (i == 0) { + reg_strict = true; + reg_alpha2 = hwsim_alpha2s[0]; + } + break; + case HWSIM_REGTEST_STRICT_AND_DRIVER_REG: + if (i == 0) { + reg_strict = true; + reg_alpha2 = hwsim_alpha2s[0]; + } else if (i == 1) { + reg_alpha2 = hwsim_alpha2s[1]; + } + break; + case HWSIM_REGTEST_ALL: + switch (i) { + case 0: + regd = &hwsim_world_regdom_custom_01; + break; + case 1: + regd = &hwsim_world_regdom_custom_02; + break; + case 2: + reg_alpha2 = hwsim_alpha2s[0]; + break; + case 3: + reg_alpha2 = hwsim_alpha2s[1]; + break; + case 4: + reg_strict = true; + reg_alpha2 = hwsim_alpha2s[2]; + break; + } + break; + default: + break; + } + + err = mac80211_hwsim_create_radio(channels, reg_alpha2, + regd, reg_strict); if (err < 0) goto out_free_radios; } diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h index fb9920a99396..2747cce5a269 100644 --- a/drivers/net/wireless/mac80211_hwsim.h +++ b/drivers/net/wireless/mac80211_hwsim.h @@ -103,6 +103,10 @@ enum { * command giving the number of channels supported by the new radio * @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO * only to destroy a radio + * @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint + * (nla string, length 2) + * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) + * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) * @__HWSIM_ATTR_MAX: enum limit */ @@ -119,6 +123,9 @@ enum { HWSIM_ATTR_COOKIE, HWSIM_ATTR_CHANNELS, HWSIM_ATTR_RADIO_ID, + HWSIM_ATTR_REG_HINT_ALPHA2, + HWSIM_ATTR_REG_CUSTOM_REG, + HWSIM_ATTR_REG_STRICT_REG, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) -- cgit v1.2.3