700 lines
24 KiB
Diff
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);
|