meta-netmodule-wlan/recipes-kernel/mac80211/mac80211/0009-netmodule-patches.patch

700 lines
24 KiB
Diff

From 6e5ef0edd3782babdeb47e7cc7b67afd3b225d95 Mon Sep 17 00:00:00 2001
From: Patrick Walther <patrick.walther@netmodule.com>
Date: Mon, 22 Mar 2021 17:52:02 +0100
Subject: [PATCH] 0007 netmodule patches
---
drivers/net/wireless/ath/ath10k/htt_rx.c | 6 +++--
drivers/net/wireless/ath/ath10k/mac.c | 40 ++++++++++++++++++++++++-------
drivers/net/wireless/ath/ath10k/pci.c | 2 +-
drivers/net/wireless/ath/regd.c | 2 +-
drivers/net/wireless/ath/regd.h | 3 ++-
drivers/net/wireless/ath/regd_common.h | 1 +
drivers/net/wireless/ti/wlcore/cmd.c | 7 ------
drivers/net/wireless/ti/wlcore/cmd.h | 1 +
drivers/net/wireless/ti/wlcore/conf.h | 3 +++
drivers/net/wireless/ti/wlcore/init.c | 22 +++++++++++++----
drivers/net/wireless/ti/wlcore/main.c | 27 +++++++++++++++------
include/net/cfg80211.h | 11 +++++++--
include/net/mac80211.h | 8 +++++--
include/uapi/linux/nl80211.h | 3 +++
net/mac80211/cfg.c | 13 ++++++++++
net/mac80211/main.c | 4 ++--
net/wireless/core.c | 41 ++++++++++++++++++++++++++------
net/wireless/nl80211.c | 13 ++++++++++
net/wireless/reg.c | 23 ++++++++++++++----
19 files changed, 180 insertions(+), 50 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 5c1af20..5f166bc 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -3683,8 +3683,10 @@ static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data)
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer || !peer->sta) {
- ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n",
- peer_id);
+ if (peer_id != 0xFF) {
+ ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n",
+ peer_id);
+ }
goto out;
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index d07a4a1..9547476 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -5097,11 +5097,13 @@ static int ath10k_start(struct ieee80211_hw *hw)
}
param = ar->wmi.pdev_param->idle_ps_config;
- ret = ath10k_wmi_pdev_set_param(ar, param, 1);
- if (ret && ret != -EOPNOTSUPP) {
- ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret);
- goto err_core_stop;
- }
+ if (param != WMI_PDEV_PARAM_UNSUPPORTED) {
+ ret = ath10k_wmi_pdev_set_param(ar, param, 1);
+ if (ret && ret != -EOPNOTSUPP) {
+ ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret);
+ goto err_core_stop;
+ }
+ }
__ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
@@ -5273,10 +5275,11 @@ static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
return 0;
}
+#define ATH10k_ADJ_POWER_DENSITY 1
static int ath10k_mac_txpower_recalc(struct ath10k *ar)
{
struct ath10k_vif *arvif;
- int ret, txpower = -1;
+ int ret, txpower = -1, pwr;
lockdep_assert_held(&ar->conf_mutex);
@@ -5285,10 +5288,28 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
if (arvif->txpower == INT_MIN)
continue;
+ pwr = arvif->txpower;
+
+ if (ar && ar->rx_channel ) {
+ if (ar->rx_channel->band == NL80211_BAND_5GHZ) {
+ pwr -= ATH10k_ADJ_POWER_DENSITY;
+ if (ar->rx_channel->flags & IEEE80211_CHAN_RADAR) {
+ pwr -= ATH10k_ADJ_POWER_DENSITY;
+ if (arvif->vif->type == NL80211_IFTYPE_STATION ||
+ arvif->vif->type == NL80211_IFTYPE_MESH_POINT) {
+ pwr -= ATH10k_ADJ_POWER_DENSITY;
+ }
+ }
+ }
+ }
+ if (pwr < 0) {
+ pwr = 0;
+ }
+
if (txpower == -1)
- txpower = arvif->txpower;
+ txpower = pwr;
else
- txpower = min(txpower, arvif->txpower);
+ txpower = min(txpower, pwr);
}
if (txpower == -1)
@@ -5303,6 +5324,7 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
return 0;
}
+#undef ATH10k_CLIENT_ADJ_POWER_DENSITY
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
{
@@ -9440,7 +9462,7 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
#endif
},
{
- .max = 1,
+ .max = 2,
.types = BIT(NL80211_IFTYPE_STATION)
},
};
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a7b6b8c..dc8c753 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -28,7 +28,7 @@ enum ath10k_pci_reset_mode {
ATH10K_PCI_RESET_WARM_ONLY = 1,
};
-static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
+static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_LEGACY;
static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 0042ea9..f7b15cf 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -733,7 +733,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
regdmn == CTRY_DEFAULT) {
printk(KERN_DEBUG "ath: EEPROM indicates default "
"country code should be used\n");
- reg->country_code = CTRY_UNITED_STATES;
+ reg->country_code = CTRY_EU;
}
if (reg->country_code == CTRY_DEFAULT) {
diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h
index 8d5a16b..bb59c9d 100644
--- a/drivers/net/wireless/ath/regd.h
+++ b/drivers/net/wireless/ath/regd.h
@@ -254,7 +254,8 @@ enum CountryCode {
CTRY_JAPAN59 = 4059,
CTRY_AUSTRALIA2 = 5000,
CTRY_CANADA2 = 5001,
- CTRY_BELGIUM2 = 5002
+ CTRY_BELGIUM2 = 5002,
+ CTRY_EU = 500,
};
bool ath_is_world_regd(struct ath_regulatory *reg);
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 364011e..4db829c 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -498,6 +498,7 @@ static struct country_code_to_enum_rd allCountries[] = {
{CTRY_VIET_NAM, NULL1_WORLD, "VN"},
{CTRY_YEMEN, NULL1_WORLD, "YE"},
{CTRY_ZIMBABWE, ETSI1_WORLD, "ZW"},
+ {CTRY_EU, ETSI1_WORLD, "EU"},
};
#endif
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 32a2e27..a82b0ee 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -1568,13 +1568,6 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif,
cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
wlvif->band));
- if (!cmd->supported_rates) {
- wl1271_debug(DEBUG_CMD,
- "peer has no supported rates yet, configuring basic rates: 0x%x",
- wlvif->basic_rate_set);
- cmd->supported_rates = cpu_to_le32(wlvif->basic_rate_set);
- }
-
wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
cmd->supported_rates, sta->uapsd_queues);
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index f2609d5..3c091e4 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -458,6 +458,7 @@ enum wl1271_cmd_key_type {
KEY_TKIP = 2,
KEY_AES = 3,
KEY_GEM = 4,
+ KEY_IGTK = 5,
};
struct wl1271_cmd_set_keys {
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index 31be425..53d40a2 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -215,6 +215,9 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
CONF_HW_BIT_RATE_11MBPS)
+#define CONF_TX_OFDM_BASIC_RATES (CONF_HW_BIT_RATE_6MBPS | \
+ CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS)
+
#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \
CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 03b49ba..5275d6b 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -425,6 +425,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
int i, ret;
struct conf_tx_rate_class rc;
u32 supported_rates;
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
wlvif->basic_rate_set);
@@ -432,16 +433,27 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (wlvif->basic_rate_set == 0)
return -EINVAL;
- rc.enabled_rates = wlvif->basic_rate_set;
- rc.long_retry_limit = 10;
- rc.short_retry_limit = 10;
- rc.aflags = 0;
+ /*In order to handle mesh PREQ/PREP loss, increase retry limit
+ and use OFDM basic rates (mgmt policy)*/
+ if (ieee80211_vif_is_mesh(vif)) {
+ rc.enabled_rates = wlvif->basic_rate_set;
+ rc.long_retry_limit = 30;
+ rc.short_retry_limit = 30;
+ rc.aflags = 0;
+ }
+ else {
+ rc.enabled_rates = wlvif->basic_rate_set;
+ rc.long_retry_limit = 10;
+ rc.short_retry_limit = 10;
+ rc.aflags = 0;
+ }
+
ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
if (ret < 0)
return ret;
/* use the min basic rate for AP broadcast/multicast */
- rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
+ rc.enabled_rates = wlvif->basic_rate;
rc.short_retry_limit = 10;
rc.long_retry_limit = 10;
rc.aflags = 0;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index b5e3a42..5cc837e 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -2271,13 +2271,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
wl12xx_allocate_rate_policy(wl,
&wlvif->ap.ucast_rate_idx[i]);
- wlvif->basic_rate_set = CONF_TX_ENABLED_RATES;
- /*
- * TODO: check if basic_rate shouldn't be
- * wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
- * instead (the same thing for STA above).
- */
- wlvif->basic_rate = CONF_TX_ENABLED_RATES;
+
+ /* For mesh set default basic rate set to OFDM basic rate set only*/
+ if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_MESH_POINT)
+ wlvif->basic_rate_set = CONF_TX_OFDM_BASIC_RATES;
+ else
+ wlvif->basic_rate_set = CONF_TX_ENABLED_RATES;
+
+ wlvif->basic_rate = wl1271_tx_min_rate_get(wl, CONF_TX_ENABLED_RATES);
+
/* TODO: this seems to be used only for STA, check it */
wlvif->rate_set = CONF_TX_ENABLED_RATES;
}
@@ -3555,6 +3557,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
key_type = KEY_AES;
key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key_type = KEY_IGTK;
+ break;
case WL1271_CIPHER_SUITE_GEM:
key_type = KEY_GEM;
break;
@@ -5811,9 +5816,16 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ u8 role_type;
s8 rssi_dbm;
int ret;
+ role_type = wl12xx_get_role_type(wl, wlvif);
+ if (role_type == WL1271_ROLE_AP ||
+ role_type == WL1271_ROLE_MESH_POINT) {
+ return;
+ }
+
wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
mutex_lock(&wl->mutex);
@@ -6227,6 +6238,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
WL1271_CIPHER_SUITE_GEM,
+ WLAN_CIPHER_SUITE_AES_CMAC,
};
/* The tx descriptor buffer */
@@ -6290,6 +6302,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
WIPHY_FLAG_IBSS_RSN;
wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN;
+ wl->hw->wiphy->features &= ~NL80211_FEATURE_FULL_AP_CLIENT_STATE;
/* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 449df09..1acf10c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -129,6 +129,7 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_4MHZ = 1<<16,
IEEE80211_CHAN_8MHZ = 1<<17,
IEEE80211_CHAN_16MHZ = 1<<18,
+ IEEE80211_CHAN_SRD = 1<<19,
};
#define IEEE80211_CHAN_NO_HT40 \
@@ -3738,6 +3739,8 @@ struct mgmt_frame_regs {
* return 0 if successful
* @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary
*
+ * @get_antenna_gain: get antenna gain
+ *
* @set_wds_peer: set the WDS peer for a WDS interface
*
* @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
@@ -4060,6 +4063,7 @@ struct cfg80211_ops {
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
int *dbm);
int (*set_antenna_gain)(struct wiphy *wiphy, int dbi);
+ int (*get_antenna_gain)(struct wiphy *wiphy, int *dbi);
int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr);
@@ -5101,6 +5105,9 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
* @requested_name: Request a particular name.
* NULL is valid value, and means use the default phy%d naming.
*
+ * @requested_index: Request a particular index.
+ * -1 is valid value, and means use the default phy%d naming.
+ *
* Create a new wiphy and associate the given operations with it.
* @sizeof_priv bytes are allocated for private use.
*
@@ -5108,7 +5115,7 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
* assigned to each netdev's ieee80211_ptr for proper operation.
*/
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
- const char *requested_name);
+ const char *requested_name, const int requested_index);
/**
* wiphy_new - create a new wiphy for use with cfg80211
@@ -5125,7 +5132,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
int sizeof_priv)
{
- return wiphy_new_nm(ops, sizeof_priv, NULL);
+ return wiphy_new_nm(ops, sizeof_priv, NULL, -1);
}
/**
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9f185ee..f9e10e3 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4228,11 +4228,15 @@ struct ieee80211_ops {
* @requested_name: Requested name for this device.
* NULL is valid value, and means use the default naming (phy%d)
*
+ * @requested_name: Requested index for this device.
+ * -1 is valid value, and means use the default naming (phy%d)
+ *
* Return: A pointer to the new hardware device, or %NULL on error.
*/
struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
const struct ieee80211_ops *ops,
- const char *requested_name);
+ const char *requested_name,
+ int requested_index);
/**
* ieee80211_alloc_hw - Allocate a new hardware device
@@ -4252,7 +4256,7 @@ static inline
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
- return ieee80211_alloc_hw_nm(priv_data_len, ops, NULL);
+ return ieee80211_alloc_hw_nm(priv_data_len, ops, NULL, -1);
}
/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 0d90183..4f5ba93 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3779,6 +3779,8 @@ enum nl80211_wmm_rule {
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_SRD_CHANNEL: short range devices mode
+ * on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3815,6 +3817,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_4MHZ,
NL80211_FREQUENCY_ATTR_8MHZ,
NL80211_FREQUENCY_ATTR_16MHZ,
+ NL80211_FREQUENCY_ATTR_SRD_CHANNEL,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 272b433..2a30e87 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2720,6 +2720,18 @@ static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi)
return 0;
}
+static int ieee80211_get_antenna_gain(struct wiphy *wiphy,
+ int *dbi)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ if (local) {
+ *dbi = local->user_antenna_gain;
+ }
+
+ return 0;
+}
+
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr)
{
@@ -4151,6 +4163,7 @@ const struct cfg80211_ops mac80211_config_ops = {
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
.set_antenna_gain = ieee80211_set_antenna_gain,
+ .get_antenna_gain = ieee80211_get_antenna_gain,
.set_wds_peer = ieee80211_set_wds_peer,
.rfkill_poll = ieee80211_rfkill_poll,
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 44076fb..293bfec 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -532,7 +532,7 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
const struct ieee80211_ops *ops,
- const char *requested_name)
+ const char *requested_name, int requested_idx)
{
struct ieee80211_local *local;
int priv_size, i;
@@ -572,7 +572,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
*/
priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
- wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name);
+ wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name, requested_idx);
if (!wiphy)
return NULL;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index afdfcc2..cefbcbc 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -123,6 +123,19 @@ static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev,
return 0;
}
+static int cfg80211_dev_check_index(const int index)
+{
+ struct cfg80211_registered_device *rdev;
+
+ ASSERT_RTNL();
+
+ /* Ensure another device does not already have this name. */
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+ if (rdev->wiphy_idx == index)
+ return -EINVAL;
+ return 0;
+}
+
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname)
{
@@ -398,7 +411,7 @@ static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
/* exported functions */
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
- const char *requested_name)
+ const char *requested_name, const int requested_index)
{
static atomic_t wiphy_counter = ATOMIC_INIT(0);
@@ -441,17 +454,31 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
rdev->ops = ops;
- rdev->wiphy_idx = atomic_inc_return(&wiphy_counter);
+ if (requested_index >= 0) {
+ int rv;
- if (unlikely(rdev->wiphy_idx < 0)) {
+ rtnl_lock();
+ rv = cfg80211_dev_check_index(requested_index);
+
+ if (rv < 0) {
+ rtnl_unlock();
+ goto use_default_index;
+ }
+ rdev->wiphy_idx = requested_index;
+ rtnl_unlock();
+ } else {
+use_default_index:
+ rdev->wiphy_idx = atomic_inc_return(&wiphy_counter);
+
+ if (unlikely(rdev->wiphy_idx < 0)) {
/* ugh, wrapped! */
atomic_dec(&wiphy_counter);
kfree(rdev);
return NULL;
- }
-
- /* atomic_inc_return makes it start at 1, make it start at 0 */
- rdev->wiphy_idx--;
+ }
+ /* atomic_inc_return makes it start at 1, make it start at 0 */
+ rdev->wiphy_idx--;
+ }
/* give it a proper name */
if (requested_name && requested_name[0]) {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 132df74..80b8caf 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1021,6 +1021,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
goto nla_put_failure;
if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_SRD) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_SRD_CHANNEL))
+ goto nla_put_failure;
}
if (chan->flags & IEEE80211_CHAN_RADAR) {
if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
@@ -3503,6 +3506,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
goto nla_put_failure;
}
+ if (rdev->ops->get_antenna_gain) {
+ int dbi = 0, ret;
+
+ ret = rdev->ops->get_antenna_gain(&rdev->wiphy, &dbi);
+ if (ret == 0 &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+ DBM_TO_MBM(dbi)))
+ goto nla_put_failure;
+ }
+
wdev_lock(wdev);
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index b6caa2b..fbe581a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -68,6 +68,7 @@
* channels allowed by the current regulatory domain.
*/
#define REG_ENFORCE_GRACE_MS 60000
+#define REG_CHANNEL_LOW_PWR_DBM 15
/**
* enum reg_request_treatment - regulatory request treatment
@@ -1788,11 +1789,21 @@ static void handle_channel_single_rule(struct wiphy *wiphy,
MBI_TO_DBI(power_rule->max_antenna_gain));
chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
+ if (chan->max_reg_power <= REG_CHANNEL_LOW_PWR_DBM) {
+ chan->flags |= IEEE80211_CHAN_SRD;
+ }
+
if (chan->flags & IEEE80211_CHAN_RADAR) {
- if (reg_rule->dfs_cac_ms)
- chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
- else
- chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+ if (reg_rule->dfs_cac_ms)
+ chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
+ else if (regd->dfs_region == NL80211_DFS_ETSI &&
+ chan->center_freq >= 5600 &&
+ chan->center_freq <= 5640) {
+ /* TDWR channels require 10 min */
+ chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS * 10;
+ } else {
+ chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
+ }
}
if (chan->orig_mpwr) {
@@ -2522,6 +2533,10 @@ static void handle_channel_custom(struct wiphy *wiphy,
}
chan->max_power = chan->max_reg_power;
+
+ if (chan->max_reg_power <= REG_CHANNEL_LOW_PWR_DBM) {
+ chan->flags |= IEEE80211_CHAN_SRD;
+ }
}
static void handle_band_custom(struct wiphy *wiphy,
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 78f2927..4fa5b0d 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -895,7 +895,8 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
/* well... oh well */
data->txpower.fixed = 1;
data->txpower.disabled = rfkill_blocked(rdev->rfkill);
- data->txpower.value = val;
+ /* show same behavior as iw and show txpower 0dBm if not initialized */
+ data->txpower.value = val == INT_MIN ? 0 : val;
data->txpower.flags = IW_TXPOW_DBM;
return 0;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index bf305b2..7998620 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -47,7 +47,7 @@ static void ieee80211_iface_work(struct work_struct *work);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_chanctx_conf *chanctx_conf;
- int power;
+ int power, max_power;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
@@ -56,7 +56,7 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
return false;
}
- power = ieee80211_chandef_max_power(&chanctx_conf->def);
+ power = max_power = ieee80211_chandef_max_power(&chanctx_conf->def);
rcu_read_unlock();
if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
@@ -65,6 +65,11 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
power = min(power, sdata->ap_power_level);
+ if (sdata->local->user_antenna_gain > 0 && sdata->local->use_chanctx) {
+ max_power -= sdata->local->user_antenna_gain;
+ power = min(power, max_power);
+ }
+
if (power != sdata->vif.bss_conf.txpower) {
sdata->vif.bss_conf.txpower = power;
ieee80211_hw_config(sdata->local, 0);