mwifiex: add custom regulatory domain support
This patch creates custom regulatory rules based on the information received from firmware and enable them during wiphy registration. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
41960b4dfd
commit
7253979910
|
@ -4141,9 +4141,12 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
||||||
wiphy->cipher_suites = mwifiex_cipher_suites;
|
wiphy->cipher_suites = mwifiex_cipher_suites;
|
||||||
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
|
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
|
||||||
|
|
||||||
if (adapter->region_code)
|
if (adapter->regd) {
|
||||||
wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
|
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
|
||||||
|
REGULATORY_DISABLE_BEACON_HINTS |
|
||||||
REGULATORY_COUNTRY_IE_IGNORE;
|
REGULATORY_COUNTRY_IE_IGNORE;
|
||||||
|
wiphy_apply_custom_regulatory(wiphy, adapter->regd);
|
||||||
|
}
|
||||||
|
|
||||||
ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
|
ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
|
||||||
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
|
||||||
|
@ -4209,19 +4212,27 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
|
if (!adapter->regd) {
|
||||||
mwifiex_dbg(adapter, INFO,
|
if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) {
|
||||||
"driver hint alpha2: %2.2s\n", reg_alpha2);
|
mwifiex_dbg(adapter, INFO,
|
||||||
regulatory_hint(wiphy, reg_alpha2);
|
"driver hint alpha2: %2.2s\n", reg_alpha2);
|
||||||
} else {
|
regulatory_hint(wiphy, reg_alpha2);
|
||||||
if (adapter->region_code == 0x00) {
|
|
||||||
mwifiex_dbg(adapter, WARN, "Ignore world regulatory domain\n");
|
|
||||||
} else {
|
} else {
|
||||||
country_code =
|
if (adapter->region_code == 0x00) {
|
||||||
mwifiex_11d_code_2_region(adapter->region_code);
|
mwifiex_dbg(adapter, WARN,
|
||||||
if (country_code &&
|
"Ignore world regulatory domain\n");
|
||||||
regulatory_hint(wiphy, country_code))
|
} else {
|
||||||
mwifiex_dbg(priv->adapter, ERROR, "regulatory_hint() failed\n");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -416,6 +416,14 @@ enum P2P_MODES {
|
||||||
P2P_MODE_CLIENT = 3,
|
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_RET_BIT 0x8000
|
||||||
#define HostCmd_ACT_GEN_GET 0x0000
|
#define HostCmd_ACT_GEN_GET 0x0000
|
||||||
#define HostCmd_ACT_GEN_SET 0x0001
|
#define HostCmd_ACT_GEN_SET 0x0001
|
||||||
|
|
|
@ -139,6 +139,8 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
|
||||||
adapter->nd_info = NULL;
|
adapter->nd_info = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kfree(adapter->regd);
|
||||||
|
|
||||||
vfree(adapter->chan_stats);
|
vfree(adapter->chan_stats);
|
||||||
kfree(adapter);
|
kfree(adapter);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1005,6 +1005,7 @@ struct mwifiex_adapter {
|
||||||
bool usb_mc_status;
|
bool usb_mc_status;
|
||||||
bool usb_mc_setup;
|
bool usb_mc_setup;
|
||||||
struct cfg80211_wowlan_nd_info *nd_info;
|
struct cfg80211_wowlan_nd_info *nd_info;
|
||||||
|
struct ieee80211_regdomain *regd;
|
||||||
};
|
};
|
||||||
|
|
||||||
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
|
void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
|
||||||
|
|
|
@ -1022,6 +1022,93 @@ static int mwifiex_ret_robust_coex(struct mwifiex_private *priv,
|
||||||
return 0;
|
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,
|
static int mwifiex_ret_chan_region_cfg(struct mwifiex_private *priv,
|
||||||
struct host_cmd_ds_command *resp)
|
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:",
|
mwifiex_dbg_dump(priv->adapter, CMD_D, "CHAN:",
|
||||||
(u8 *)head + sizeof(*head),
|
(u8 *)head + sizeof(*head),
|
||||||
tlv_buf_len);
|
tlv_buf_len);
|
||||||
|
priv->adapter->regd =
|
||||||
|
mwifiex_create_custom_regdomain(priv,
|
||||||
|
(u8 *)head +
|
||||||
|
sizeof(*head), tlv_buf_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue