From: Xinming Hu <[email protected]>
AID gets updated during TDLS setup, but modified value isn't reflected
in "priv->assoc_rsp_buf". This causes TDLS setup failure. The problem is
fixed here.
Fixes: 4aff53ef18e4a4 ("mwifiex: parsing aid while receiving..")
Signed-off-by: Xinming Hu <[email protected]>
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/join.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c
index 1c7b006..b89596c 100644
--- a/drivers/net/wireless/marvell/mwifiex/join.c
+++ b/drivers/net/wireless/marvell/mwifiex/join.c
@@ -669,9 +669,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
sizeof(priv->assoc_rsp_buf));
- memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
-
assoc_rsp->a_id = cpu_to_le16(aid);
+ memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
if (status_code) {
priv->adapter->dbg.num_cmd_assoc_failure++;
--
1.9.1
This patch creates custom regulatory rules based on the information
received from firmware and enable them during wiphy registration.
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 39 ++++++----
drivers/net/wireless/marvell/mwifiex/fw.h | 8 ++
drivers/net/wireless/marvell/mwifiex/main.c | 2 +
drivers/net/wireless/marvell/mwifiex/main.h | 1 +
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c | 91 ++++++++++++++++++++++
5 files changed, 127 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 86b31b1..a91d442 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4224,9 +4224,12 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->cipher_suites = mwifiex_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
- if (adapter->region_code)
- wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
+ if (adapter->regd) {
+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+ REGULATORY_DISABLE_BEACON_HINTS |
REGULATORY_COUNTRY_IE_IGNORE;
+ wiphy_apply_custom_regulatory(wiphy, adapter->regd);
+ }
ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
@@ -4292,19 +4295,27 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
return ret;
}
- if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
- mwifiex_dbg(adapter, INFO,
- "driver hint alpha2: %2.2s\n", reg_alpha2);
- regulatory_hint(wiphy, reg_alpha2);
- } else {
- if (adapter->region_code == 0x00) {
- mwifiex_dbg(adapter, WARN, "Ignore world regulatory domain\n");
+ if (!adapter->regd) {
+ if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
+ mwifiex_dbg(adapter, INFO,
+ "driver hint alpha2: %2.2s\n", reg_alpha2);
+ regulatory_hint(wiphy, reg_alpha2);
} else {
- country_code =
- mwifiex_11d_code_2_region(adapter->region_code);
- if (country_code &&
- regulatory_hint(wiphy, country_code))
- mwifiex_dbg(priv->adapter, ERROR, "regulatory_hint() failed\n");
+ if (adapter->region_code == 0x00) {
+ mwifiex_dbg(adapter, WARN,
+ "Ignore world regulatory domain\n");
+ } else {
+ wiphy->regulatory_flags |=
+ REGULATORY_DISABLE_BEACON_HINTS |
+ REGULATORY_COUNTRY_IE_IGNORE;
+ country_code =
+ mwifiex_11d_code_2_region(
+ adapter->region_code);
+ if (country_code &&
+ regulatory_hint(wiphy, country_code))
+ mwifiex_dbg(priv->adapter, ERROR,
+ "regulatory_hint() failed\n");
+ }
}
}
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index 085db99..18aa525 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -416,6 +416,14 @@ enum P2P_MODES {
P2P_MODE_CLIENT = 3,
};
+enum mwifiex_channel_flags {
+ MWIFIEX_CHANNEL_PASSIVE = BIT(0),
+ MWIFIEX_CHANNEL_DFS = BIT(1),
+ MWIFIEX_CHANNEL_NOHT40 = BIT(2),
+ MWIFIEX_CHANNEL_NOHT80 = BIT(3),
+ MWIFIEX_CHANNEL_DISABLED = BIT(7),
+};
+
#define HostCmd_RET_BIT 0x8000
#define HostCmd_ACT_GEN_GET 0x0000
#define HostCmd_ACT_GEN_SET 0x0001
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index 0181247..7f2fb81 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -143,6 +143,8 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
adapter->nd_info = NULL;
}
+ kfree(adapter->regd);
+
vfree(adapter->chan_stats);
kfree(adapter);
return 0;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 2d32768..26df28f 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -1009,6 +1009,7 @@ struct mwifiex_adapter {
bool usb_mc_status;
bool usb_mc_setup;
struct cfg80211_wowlan_nd_info *nd_info;
+ struct ieee80211_regdomain *regd;
};
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
index db85330..3344a26 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
@@ -1022,6 +1022,93 @@ static int mwifiex_ret_robust_coex(struct mwifiex_private *priv,
return 0;
}
+static struct ieee80211_regdomain *
+mwifiex_create_custom_regdomain(struct mwifiex_private *priv,
+ u8 *buf, u16 buf_len)
+{
+ u16 num_chan = buf_len / 2;
+ struct ieee80211_regdomain *regd;
+ struct ieee80211_reg_rule *rule;
+ bool new_rule;
+ int regd_size, idx, freq, prev_freq = 0;
+ u32 bw, prev_bw = 0;
+ u8 chflags, prev_chflags = 0, valid_rules = 0;
+
+ if (WARN_ON_ONCE(num_chan > NL80211_MAX_SUPP_REG_RULES))
+ return ERR_PTR(-EINVAL);
+
+ regd_size = sizeof(struct ieee80211_regdomain) +
+ num_chan * sizeof(struct ieee80211_reg_rule);
+
+ regd = kzalloc(regd_size, GFP_KERNEL);
+ if (!regd)
+ return ERR_PTR(-ENOMEM);
+
+ for (idx = 0; idx < num_chan; idx++) {
+ u8 chan;
+ enum nl80211_band band;
+
+ chan = *buf++;
+ if (!chan)
+ return NULL;
+ chflags = *buf++;
+ band = (chan <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(chan, band);
+ new_rule = false;
+
+ if (chflags & MWIFIEX_CHANNEL_DISABLED)
+ continue;
+
+ if (band == NL80211_BAND_5GHZ) {
+ if (!(chflags & MWIFIEX_CHANNEL_NOHT80))
+ bw = MHZ_TO_KHZ(80);
+ else if (!(chflags & MWIFIEX_CHANNEL_NOHT40))
+ bw = MHZ_TO_KHZ(40);
+ else
+ bw = MHZ_TO_KHZ(20);
+ } else {
+ if (!(chflags & MWIFIEX_CHANNEL_NOHT40))
+ bw = MHZ_TO_KHZ(40);
+ else
+ bw = MHZ_TO_KHZ(20);
+ }
+
+ if (idx == 0 || prev_chflags != chflags || prev_bw != bw ||
+ freq - prev_freq > 20) {
+ valid_rules++;
+ new_rule = true;
+ }
+
+ rule = ®d->reg_rules[valid_rules - 1];
+
+ rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
+
+ prev_chflags = chflags;
+ prev_freq = freq;
+ prev_bw = bw;
+
+ if (!new_rule)
+ continue;
+
+ rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10);
+ rule->power_rule.max_eirp = DBM_TO_MBM(19);
+
+ if (chflags & MWIFIEX_CHANNEL_PASSIVE)
+ rule->flags = NL80211_RRF_NO_IR;
+
+ if (chflags & MWIFIEX_CHANNEL_DFS)
+ rule->flags = NL80211_RRF_DFS;
+
+ rule->freq_range.max_bandwidth_khz = bw;
+ }
+
+ regd->n_reg_rules = valid_rules;
+ regd->alpha2[0] = '9';
+ regd->alpha2[1] = '9';
+
+ return regd;
+}
+
static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
@@ -1050,6 +1137,10 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
mwifiex_dbg_dump(priv->adapter, CMD_D, "CHAN:",
(u8 *)head + sizeof(*head),
tlv_buf_len);
+ priv->adapter->regd =
+ mwifiex_create_custom_regdomain(priv,
+ (u8 *)head +
+ sizeof(*head), tlv_buf_len);
break;
}
--
1.9.1
This patch adds command preparation and response handling for
CHAN_REGION_CFG command. These changes are prerequisites for adding
custom regulatory domain support.
Signed-off-by: Amitkumar Karwar <[email protected]>
---
drivers/net/wireless/marvell/mwifiex/fw.h | 7 ++++
drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 21 +++++++++++
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c | 41 ++++++++++++++++++++++
3 files changed, 69 insertions(+)
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index a88030a..085db99 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -190,6 +190,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203)
#define TLV_TYPE_BSS_MODE (PROPRIETARY_TLV_BASE_ID + 206)
#define TLV_TYPE_RANDOM_MAC (PROPRIETARY_TLV_BASE_ID + 236)
+#define TLV_TYPE_CHAN_ATTR_CFG (PROPRIETARY_TLV_BASE_ID + 237)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -382,6 +383,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_MC_POLICY 0x0121
#define HostCmd_CMD_TDLS_OPER 0x0122
#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223
+#define HostCmd_CMD_CHAN_REGION_CFG 0x0242
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
@@ -2224,6 +2226,10 @@ struct host_cmd_ds_gtk_rekey_params {
__le32 replay_ctr_high;
} __packed;
+struct host_cmd_ds_chan_region_cfg {
+ __le16 action;
+} __packed;
+
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@@ -2298,6 +2304,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_robust_coex coex;
struct host_cmd_ds_wakeup_reason hs_wakeup_reason;
struct host_cmd_ds_gtk_rekey_params rekey;
+ struct host_cmd_ds_chan_region_cfg reg_cfg;
} params;
} __packed;
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
index 1d8f284..49048b4 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c
@@ -1594,6 +1594,21 @@ static int mwifiex_cmd_gtk_rekey_offload(struct mwifiex_private *priv,
return 0;
}
+static int mwifiex_cmd_chan_region_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct host_cmd_ds_chan_region_cfg *reg = &cmd->params.reg_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REGION_CFG);
+ cmd->size = cpu_to_le16(sizeof(*reg) + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET)
+ reg->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
static int
mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
@@ -2134,6 +2149,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
ret = mwifiex_cmd_gtk_rekey_offload(priv, cmd_ptr, cmd_action,
data_buf);
break;
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ ret = mwifiex_cmd_chan_region_cfg(priv, cmd_ptr, cmd_action);
+ break;
default:
mwifiex_dbg(priv->adapter, ERROR,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -2271,6 +2289,9 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
if (ret)
return -1;
}
+
+ mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REGION_CFG,
+ HostCmd_ACT_GEN_GET, 0, NULL, true);
}
/* get tx rate */
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
index 90e191b..db85330 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
@@ -1022,6 +1022,44 @@ static int mwifiex_ret_robust_coex(struct mwifiex_private *priv,
return 0;
}
+static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_chan_region_cfg *reg = &resp->params.reg_cfg;
+ u16 action = le16_to_cpu(reg->action);
+ u16 tlv, tlv_buf_len, tlv_buf_left;
+ struct mwifiex_ie_types_header *head;
+ u8 *tlv_buf;
+
+ if (action != HostCmd_ACT_GEN_GET)
+ return 0;
+
+ tlv_buf = (u8 *)reg + sizeof(*reg);
+ tlv_buf_left = le16_to_cpu(resp->size) - S_DS_GEN - sizeof(*reg);
+
+ while (tlv_buf_left >= sizeof(*head)) {
+ head = (struct mwifiex_ie_types_header *)tlv_buf;
+ tlv = le16_to_cpu(head->type);
+ tlv_buf_len = le16_to_cpu(head->len);
+
+ if (tlv_buf_left < (sizeof(*head) + tlv_buf_len))
+ break;
+
+ switch (tlv) {
+ case TLV_TYPE_CHAN_ATTR_CFG:
+ mwifiex_dbg_dump(priv->adapter, CMD_D, "CHAN:",
+ (u8 *)head + sizeof(*head),
+ tlv_buf_len);
+ break;
+ }
+
+ tlv_buf += (sizeof(*head) + tlv_buf_len);
+ tlv_buf_left -= (sizeof(*head) + tlv_buf_len);
+ }
+
+ return 0;
+}
+
/*
* This function handles the command responses.
*
@@ -1239,6 +1277,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break;
case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG:
break;
+ case HostCmd_CMD_CHAN_REGION_CFG:
+ ret = mwifiex_ret_chan_region_cfg(priv, resp);
+ break;
default:
mwifiex_dbg(adapter, ERROR,
"CMD_RESP: unknown cmd response %#x\n",
--
1.9.1
On Tue, Aug 09, 2016 at 08:20:46PM +0530, Amitkumar Karwar wrote:
> This patch creates custom regulatory rules based on the information
> received from firmware and enable them during wiphy registration.
>
> Signed-off-by: Amitkumar Karwar <[email protected]>
Hi,
This patch recently landed in wireless-testing but I noticed (or well,
smatch noticed) some issues with the error paths:
> + if (adapter->regd) {
does null-check here and elsewhere...
> +static struct ieee80211_regdomain *
> +mwifiex_create_custom_regdomain(struct mwifiex_private *priv,
> + u8 *buf, u16 buf_len)
> +{
> + u16 num_chan = buf_len / 2;
> + struct ieee80211_regdomain *regd;
> + struct ieee80211_reg_rule *rule;
> + bool new_rule;
> + int regd_size, idx, freq, prev_freq = 0;
> + u32 bw, prev_bw = 0;
> + u8 chflags, prev_chflags = 0, valid_rules = 0;
> +
> + if (WARN_ON_ONCE(num_chan > NL80211_MAX_SUPP_REG_RULES))
> + return ERR_PTR(-EINVAL);
> +
...returns ERR_PTR here
> + regd_size = sizeof(struct ieee80211_regdomain) +
> + num_chan * sizeof(struct ieee80211_reg_rule);
> +
> + regd = kzalloc(regd_size, GFP_KERNEL);
> + if (!regd)
> + return ERR_PTR(-ENOMEM);
and here.
> +
> + for (idx = 0; idx < num_chan; idx++) {
> + u8 chan;
> + enum nl80211_band band;
> +
> + chan = *buf++;
> + if (!chan)
> + return NULL;
^ here, returns null, leaking regd
> + chflags = *buf++;
> + band = (chan <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
> + freq = ieee80211_channel_to_frequency(chan, band);
> + new_rule = false;
> +
> + if (chflags & MWIFIEX_CHANNEL_DISABLED)
> + continue;
> +
> + if (band == NL80211_BAND_5GHZ) {
> + if (!(chflags & MWIFIEX_CHANNEL_NOHT80))
> + bw = MHZ_TO_KHZ(80);
> + else if (!(chflags & MWIFIEX_CHANNEL_NOHT40))
> + bw = MHZ_TO_KHZ(40);
> + else
> + bw = MHZ_TO_KHZ(20);
> + } else {
> + if (!(chflags & MWIFIEX_CHANNEL_NOHT40))
> + bw = MHZ_TO_KHZ(40);
> + else
> + bw = MHZ_TO_KHZ(20);
> + }
> +
> + if (idx == 0 || prev_chflags != chflags || prev_bw != bw ||
> + freq - prev_freq > 20) {
> + valid_rules++;
> + new_rule = true;
> + }
> +
> + rule = ®d->reg_rules[valid_rules - 1];
> +
> + rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
> +
> + prev_chflags = chflags;
> + prev_freq = freq;
> + prev_bw = bw;
> +
> + if (!new_rule)
> + continue;
> +
> + rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10);
> + rule->power_rule.max_eirp = DBM_TO_MBM(19);
> +
> + if (chflags & MWIFIEX_CHANNEL_PASSIVE)
> + rule->flags = NL80211_RRF_NO_IR;
> +
> + if (chflags & MWIFIEX_CHANNEL_DFS)
> + rule->flags = NL80211_RRF_DFS;
> +
> + rule->freq_range.max_bandwidth_khz = bw;
> + }
> +
> + regd->n_reg_rules = valid_rules;
> + regd->alpha2[0] = '9';
> + regd->alpha2[1] = '9';
> +
> + return regd;
> +}
[...]
> static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
> struct host_cmd_ds_command *resp)
> {
> @@ -1050,6 +1137,10 @@ static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
> mwifiex_dbg_dump(priv->adapter, CMD_D, "CHAN:",
> (u8 *)head + sizeof(*head),
> tlv_buf_len);
> + priv->adapter->regd =
> + mwifiex_create_custom_regdomain(priv,
> + (u8 *)head +
> + sizeof(*head), tlv_buf_len);
Here regd is assigned without checking IS_ERR.
--
Bob Copeland %% http://bobcopeland.com/
Amitkumar Karwar <[email protected]> wrote:
> From: Xinming Hu <[email protected]>
>
> AID gets updated during TDLS setup, but modified value isn't reflected
> in "priv->assoc_rsp_buf". This causes TDLS setup failure. The problem is
> fixed here.
>
> Fixes: 4aff53ef18e4a4 ("mwifiex: parsing aid while receiving..")
> Signed-off-by: Xinming Hu <[email protected]>
> Signed-off-by: Amitkumar Karwar <[email protected]>
Thanks, 3 patches applied to wireless-drivers-next.git:
b64db1b252e9 mwifiex: correct aid value during tdls setup
41960b4dfdfc mwifiex: add CHAN_REGION_CFG command
72539799104d mwifiex: add custom regulatory domain support
--
Sent by pwcli
https://patchwork.kernel.org/patch/9271429/