qcacld-3.0: Add 6GHz support for VENDOR_SUBCMD_EXTERNAL_ACS

As a part of 6GHz support, add support to parse and send channel
frequency (in MHz) in QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS
command/event data.

Change-Id: I87879b4f8dd6a5c4ded2e89c527ba91432c9c48a
CRs-Fixed: 2533732
This commit is contained in:
Rajeev Kumar Sirasanagandla 2019-09-05 22:30:44 +05:30 • committed by nshrivas
commit 95f202a55b
2 changed files with 435 additions and 134 deletions

View file

@ -1877,12 +1877,12 @@ struct hdd_context {
/**
* struct hdd_vendor_acs_chan_params - vendor acs channel parameters
* @pcl_count: pcl list count
* @vendor_pcl_list: pointer to pcl list
* @vendor_pcl_list: pointer to pcl frequency (MHz) list
* @vendor_weight_list: pointer to pcl weight list
*/
struct hdd_vendor_acs_chan_params {
uint32_t pcl_count;
uint8_t *vendor_pcl_list;
uint32_t *vendor_pcl_list;
uint8_t *vendor_weight_list;
};
@ -1899,18 +1899,18 @@ struct hdd_external_acs_timer_context {
/**
* struct hdd_vendor_chan_info - vendor channel info
* @band: channel operating band
* @pri_ch: primary channel
* @ht_sec_ch: secondary channel
* @vht_seg0_center_ch: segment0 for vht
* @vht_seg1_center_ch: vht segment 1
* @pri_chan_freq: primary channel freq in MHz
* @ht_sec_chan_freq: secondary channel freq in MHz
* @vht_seg0_center_chan_freq: segment0 for vht in MHz
* @vht_seg1_center_chan_freq: vht segment 1 in MHz
* @chan_width: channel width
*/
struct hdd_vendor_chan_info {
uint8_t band;
uint8_t pri_ch;
uint8_t ht_sec_ch;
uint8_t vht_seg0_center_ch;
uint8_t vht_seg1_center_ch;
uint32_t pri_chan_freq;
uint32_t ht_sec_chan_freq;
uint32_t vht_seg0_center_chan_freq;
uint32_t vht_seg1_center_chan_freq;
uint8_t chan_width;
};

View file

@ -2003,8 +2003,7 @@ static void hdd_update_vendor_pcl_list(struct hdd_context *hdd_ctx,
*/
for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) {
acs_chan_params->vendor_pcl_list[i] =
wlan_reg_freq_to_chan(hdd_ctx->pdev,
sap_config->acs_cfg.freq_list[i]);
sap_config->acs_cfg.freq_list[i];
acs_chan_params->vendor_weight_list[i] = 0;
for (j = 0; j < sap_config->acs_cfg.pcl_ch_count; j++) {
if (sap_config->acs_cfg.freq_list[i] ==
@ -2023,13 +2022,13 @@ static void hdd_update_vendor_pcl_list(struct hdd_context *hdd_ctx,
* for all the given channel
* @adapter: pointer to SAP adapter struct
* @channel_count: channel count
* @channel_list: channel list
* @freq_list: channel frequency (MHz) list
*
* Return: Status of of channel information updation
*/
static int hdd_update_reg_chan_info(struct hdd_adapter *adapter,
uint32_t channel_count,
uint8_t *channel_list)
static int
hdd_update_reg_chan_info(struct hdd_adapter *adapter,
uint32_t channel_count, uint32_t *freq_list)
{
int i;
struct hdd_channel_info *icv;
@ -2051,8 +2050,8 @@ static int hdd_update_reg_chan_info(struct hdd_adapter *adapter,
for (i = 0; i < channel_count; i++) {
icv = &sap_config->channel_info[i];
chan = channel_list[i];
chan = wlan_reg_freq_to_chan(hdd_ctx->pdev,
freq_list[i]);
if (chan == 0)
continue;
@ -2080,7 +2079,8 @@ static int hdd_update_reg_chan_info(struct hdd_adapter *adapter,
}
icv->flags = 0;
icv->flags = cds_get_vendor_reg_flags(hdd_ctx->pdev, chan,
icv->flags = cds_get_vendor_reg_flags(hdd_ctx->pdev,
icv->ieee_chan_number,
sap_config->acs_cfg.ch_width,
sap_config->acs_cfg.is_ht_enabled,
sap_config->acs_cfg.is_vht_enabled,
@ -2121,8 +2121,14 @@ static int hdd_update_reg_chan_info(struct hdd_adapter *adapter,
#define CHAN_INFO_ATTR_VHT_SEG_1 \
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1
#define CHAN_INFO_ATTR_FREQ_VHT_SEG_0 \
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0
#define CHAN_INFO_ATTR_FREQ_VHT_SEG_1 \
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1
/**
* hdd_cfg80211_update_channel_info() - add channel info attributes
* @hdd_ctx: pointer to hdd context
* @skb: pointer to sk buff
* @hdd_ctx: pointer to hdd station context
* @idx: attribute index
@ -2130,12 +2136,14 @@ static int hdd_update_reg_chan_info(struct hdd_adapter *adapter,
* Return: Success(0) or reason code for failure
*/
static int32_t
hdd_cfg80211_update_channel_info(struct sk_buff *skb,
struct sap_config *sap_config, int idx)
hdd_cfg80211_update_channel_info(struct hdd_context *hdd_ctx,
struct sk_buff *skb,
struct sap_config *sap_config, int idx)
{
struct nlattr *nla_attr, *channel;
struct hdd_channel_info *icv;
int i;
uint32_t freq_seg_0, freq_seg_1;
nla_attr = nla_nest_start(skb, idx);
if (!nla_attr)
@ -2151,6 +2159,14 @@ hdd_cfg80211_update_channel_info(struct sk_buff *skb,
hdd_err("channel info not found");
goto fail;
}
freq_seg_0 = wlan_reg_legacy_chan_to_freq(
hdd_ctx->pdev,
icv->vht_center_freq_seg0);
freq_seg_1 = wlan_reg_legacy_chan_to_freq(
hdd_ctx->pdev,
icv->vht_center_freq_seg1);
if (nla_put_u16(skb, CHAN_INFO_ATTR_FREQ,
icv->freq) ||
nla_put_u32(skb, CHAN_INFO_ATTR_FLAGS,
@ -2170,7 +2186,11 @@ hdd_cfg80211_update_channel_info(struct sk_buff *skb,
nla_put_u8(skb, CHAN_INFO_ATTR_VHT_SEG_0,
icv->vht_center_freq_seg0) ||
nla_put_u8(skb, CHAN_INFO_ATTR_VHT_SEG_1,
icv->vht_center_freq_seg1)) {
icv->vht_center_freq_seg1) ||
nla_put_u32(skb, CHAN_INFO_ATTR_FREQ_VHT_SEG_0,
freq_seg_0) ||
nla_put_u32(skb, CHAN_INFO_ATTR_FREQ_VHT_SEG_1,
freq_seg_1)) {
hdd_err("put fail");
goto fail;
}
@ -2193,8 +2213,12 @@ fail:
#undef CHAN_INFO_ATTR_VHT_SEG_0
#undef CHAN_INFO_ATTR_VHT_SEG_1
#undef CHAN_INFO_ATTR_FREQ_VHT_SEG_0
#undef CHAN_INFO_ATTR_FREQ_VHT_SEG_1
/**
* hdd_cfg80211_update_pcl() - add pcl info attributes
* @hdd_ctx: pointer to hdd context
* @skb: pointer to sk buff
* @hdd_ctx: pointer to hdd station context
* @idx: attribute index
@ -2204,15 +2228,16 @@ fail:
* Return: Success(0) or reason code for failure
*/
static int32_t
hdd_cfg80211_update_pcl(struct sk_buff *skb,
hdd_cfg80211_update_pcl(struct hdd_context *hdd_ctx,
struct sk_buff *skb,
uint8_t ch_list_count, int idx,
uint8_t *vendor_pcl_list, uint8_t *vendor_weight_list)
uint32_t *vendor_pcl_list, uint8_t *vendor_weight_list)
{
struct nlattr *nla_attr, *channel;
int i;
uint8_t chan;
nla_attr = nla_nest_start(skb, idx);
if (!nla_attr)
goto fail;
@ -2220,8 +2245,13 @@ hdd_cfg80211_update_pcl(struct sk_buff *skb,
channel = nla_nest_start(skb, i);
if (!channel)
goto fail;
if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL,
vendor_pcl_list[i]) ||
chan = (uint8_t)wlan_reg_freq_to_chan(hdd_ctx->pdev,
vendor_pcl_list[i]);
if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL, chan) ||
nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_PCL_FREQ,
vendor_pcl_list[i]) ||
nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT,
vendor_weight_list[i])) {
hdd_err("put fail");
@ -2256,7 +2286,7 @@ static void hdd_get_scan_band(struct hdd_context *hdd_ctx,
* wlan_hdd_sap_get_valid_channellist() - Get SAPs valid channel list
* @ap_adapter: adapter
* @channel_count: valid channel count
* @channel_list: valid channel list
* @freq_list: valid channel frequency (MHz) list
* @band: frequency band
*
* This API returns valid channel list for SAP after removing nol and
@ -2266,18 +2296,16 @@ static void hdd_get_scan_band(struct hdd_context *hdd_ctx,
*/
static int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter,
uint32_t *channel_count,
uint8_t *channel_list,
uint32_t *freq_list,
enum band_info band)
{
struct sap_config *sap_config;
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
uint8_t tmp_chan_list[QDF_MAX_NUM_CHAN] = {0};
uint32_t pcl_freqs[QDF_MAX_NUM_CHAN] = {0};
uint32_t chan_count;
uint8_t i;
uint32_t i;
QDF_STATUS status;
struct wlan_objmgr_pdev *pdev = hdd_ctx->pdev;
uint8_t tmp_chan;
sap_config = &adapter->session.ap.sap_config;
@ -2288,25 +2316,23 @@ static int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter,
hdd_err("Failed to get channel list");
return -EINVAL;
}
for (i = 0; i < chan_count; i++)
tmp_chan_list[i] = wlan_freq_to_chan(pcl_freqs[i]);
*channel_count = 0;
for (i = 0; i < chan_count; i++) {
tmp_chan = tmp_chan_list[i];
if (*channel_count < QDF_MAX_NUM_CHAN) {
if ((band == BAND_2G) &&
(WLAN_REG_IS_24GHZ_CH(tmp_chan)) &&
(!wlan_reg_is_disable_ch(pdev, tmp_chan))) {
channel_list[*channel_count] = tmp_chan;
*channel_count += 1;
} else if ((band == BAND_5G) &&
(WLAN_REG_IS_5GHZ_CH(tmp_chan)) &&
(!wlan_reg_is_disable_ch(pdev, tmp_chan))) {
channel_list[*channel_count] = tmp_chan;
*channel_count += 1;
}
} else {
if (*channel_count >= QDF_MAX_NUM_CHAN)
break;
if (band == BAND_2G &&
WLAN_REG_IS_24GHZ_CH_FREQ(pcl_freqs[i]) &&
!wlan_reg_is_disable_for_freq(pdev, pcl_freqs[i])) {
freq_list[*channel_count] = pcl_freqs[i];
*channel_count += 1;
} else if (band == BAND_5G &&
(WLAN_REG_IS_5GHZ_CH_FREQ(pcl_freqs[i]) ||
WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl_freqs[i])) &&
!wlan_reg_is_disable_for_freq(pdev, pcl_freqs[i])) {
freq_list[*channel_count] = pcl_freqs[i];
*channel_count += 1;
}
}
@ -2318,24 +2344,111 @@ static int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter,
return 0;
}
/**
* hdd_get_external_acs_event_len() - Get event buffer length for external ACS
* @channel_count: number of channels for ACS operation
*
* Return: External ACS event (SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG) buffer length.
*/
static int hdd_get_external_acs_event_len(uint32_t channel_count)
{
uint32_t len = NLMSG_HDRLEN;
uint32_t i;
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON */
len += nla_total_size(sizeof(u8));
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED */
len += nla_total_size(sizeof(u32));
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT */
len += nla_total_size(sizeof(u32));
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_WIDTH */
len += nla_total_size(sizeof(u8));
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND */
len += nla_total_size(sizeof(u8));
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE */
len += nla_total_size(sizeof(u32));
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_FREQ_LIST */
len += nla_total_size(channel_count * sizeof(u32));
for (i = 0; i < channel_count; i++) {
/* QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL */
len += nla_total_size(sizeof(u8));
/* QCA_WLAN_VENDOR_ATTR_PCL_FREQ */
len += nla_total_size(sizeof(u32));
/* QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT */
len += nla_total_size(sizeof(u8));
}
for (i = 0; i < channel_count; i++) {
/* QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ */
len += nla_total_size(sizeof(u16));
/* QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS */
len += nla_total_size(sizeof(u32));
/* QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT */
len += nla_total_size(sizeof(u32));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_REG_POWER */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_POWER */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MIN_POWER */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_REG_CLASS_ID */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_ANTENNA_GAIN */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0 */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1 */
len += nla_total_size(sizeof(u8));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 */
len += nla_total_size(sizeof(u32));
/* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 */
len += nla_total_size(sizeof(u32));
}
/* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY */
len += nla_total_size(sizeof(u32));
return len;
}
int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter,
uint8_t reason)
{
struct sk_buff *skb;
struct sap_config *sap_config;
uint32_t channel_count = 0, status = -EINVAL;
uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0};
uint32_t freq_list[QDF_MAX_NUM_CHAN] = {0};
uint8_t vendor_pcl_list[QDF_MAX_NUM_CHAN] = {0};
uint32_t vendor_pcl_list[QDF_MAX_NUM_CHAN] = {0};
uint8_t vendor_weight_list[QDF_MAX_NUM_CHAN] = {0};
struct hdd_vendor_acs_chan_params acs_chan_params;
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
enum band_info band = BAND_2G;
eCsrPhyMode phy_mode;
enum qca_wlan_vendor_attr_external_acs_policy acs_policy;
uint32_t i;
uint32_t i, id;
QDF_STATUS qdf_status;
bool is_external_acs_policy = cfg_default(CFG_EXTERNAL_ACS_POLICY);
uint32_t len;
if (!hdd_ctx) {
hdd_err("HDD context is NULL");
@ -2376,14 +2489,13 @@ int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter,
if (sap_config->acs_cfg.freq_list) {
/* Copy INI or hostapd provided ACS channel range*/
for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++)
channel_list[i] = wlan_reg_freq_to_chan(hdd_ctx->pdev,
sap_config->acs_cfg.freq_list[i]);
freq_list[i] = sap_config->acs_cfg.freq_list[i];
channel_count = sap_config->acs_cfg.ch_list_count;
} else {
/* No channel list provided, copy all valid channels */
wlan_hdd_sap_get_valid_channellist(adapter,
&channel_count,
channel_list,
freq_list,
band);
}
@ -2393,19 +2505,15 @@ int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter,
if (!sap_config->channel_info)
return -ENOMEM;
hdd_update_reg_chan_info(adapter, channel_count, channel_list);
hdd_update_reg_chan_info(adapter, channel_count, freq_list);
qdf_mem_copy(freq_list, sap_config->acs_cfg.freq_list,
sizeof(uint32_t) * sap_config->acs_cfg.ch_list_count);
/* Get phymode */
phy_mode = adapter->session.ap.sap_config.acs_cfg.hw_mode;
skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
&(adapter->wdev),
EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
QCA_NL80211_VENDOR_SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG,
GFP_KERNEL);
len = hdd_get_external_acs_event_len(channel_count);
id = QCA_NL80211_VENDOR_SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG;
skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, &adapter->wdev,
len, id, GFP_KERNEL);
if (!skb) {
hdd_err("cfg80211_vendor_event_alloc failed");
qdf_mem_free(sap_config->channel_info);
@ -2426,7 +2534,7 @@ int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter,
hdd_debug("ACS PCL list: len: %d",
acs_chan_params.pcl_count);
for (i = 0; i < acs_chan_params.pcl_count; i++)
hdd_debug("channel:%d, weight:%d ",
hdd_debug("channel_frequency: %u, weight: %u",
acs_chan_params.
vendor_pcl_list[i],
acs_chan_params.
@ -2465,7 +2573,7 @@ int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter,
goto fail;
}
status =
hdd_cfg80211_update_pcl(skb,
hdd_cfg80211_update_pcl(hdd_ctx, skb,
acs_chan_params.pcl_count,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL,
vendor_pcl_list,
@ -2474,9 +2582,9 @@ int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter,
if (status != 0)
goto fail;
status = hdd_cfg80211_update_channel_info(skb, sap_config,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO);
id = QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO;
status = hdd_cfg80211_update_channel_info(hdd_ctx, skb, sap_config, id);
if (status != 0)
goto fail;
@ -10992,22 +11100,23 @@ static int __wlan_hdd_cfg80211_setband(struct wiphy *wiphy,
}
/**
*wlan_hdd_validate_acs_channel() - validate channel provided by ACS
*wlan_hdd_validate_acs_channel() - validate channel frequency provided by ACS
* @adapter: hdd adapter
* @channel: channel number
* @chan_freq: channel frequency in MHz
*
* return: QDF status based on success or failure
*/
static QDF_STATUS wlan_hdd_validate_acs_channel(struct hdd_adapter *adapter,
int channel, int chan_bw)
uint32_t chan_freq, int chan_bw)
{
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
uint8_t channel;
if (QDF_STATUS_SUCCESS !=
wlan_hdd_validate_operation_channel(adapter,
wlan_reg_chan_to_freq(
hdd_ctx->pdev, channel)))
wlan_hdd_validate_operation_channel(adapter, chan_freq))
return QDF_STATUS_E_FAILURE;
channel = (uint8_t)wlan_reg_freq_to_chan(hdd_ctx->pdev, chan_freq);
if ((wlansap_is_channel_in_nol_list(WLAN_HDD_GET_SAP_CTX_PTR(adapter),
channel,
PHY_SINGLE_CHANNEL_CENTERED))) {
@ -11034,15 +11143,19 @@ static void hdd_update_acs_sap_config(struct hdd_context *hdd_ctx,
QDF_STATUS status;
uint32_t channel_bonding_mode;
sap_config->chan_freq = wlan_reg_chan_to_freq(hdd_ctx->pdev,
channel_list->pri_ch);
sap_config->chan_freq = channel_list->pri_chan_freq;
sap_config->ch_params.center_freq_seg0 =
channel_list->vht_seg0_center_ch;
wlan_reg_freq_to_chan(hdd_ctx->pdev,
channel_list->vht_seg0_center_chan_freq);
sap_config->ch_params.center_freq_seg1 =
channel_list->vht_seg1_center_ch;
wlan_reg_freq_to_chan(hdd_ctx->pdev,
channel_list->vht_seg1_center_chan_freq);
sap_config->ch_params.sec_ch_offset =
wlan_reg_freq_to_chan(hdd_ctx->pdev,
channel_list->ht_sec_chan_freq);
sap_config->ch_params.sec_ch_offset = channel_list->ht_sec_ch;
sap_config->ch_params.ch_width = channel_list->chan_width;
if (WLAN_REG_IS_5GHZ_CH_FREQ(sap_config->chan_freq)) {
status =
@ -11057,18 +11170,14 @@ static void hdd_update_acs_sap_config(struct hdd_context *hdd_ctx,
sap_config->ch_width_orig = channel_bonding_mode ?
eHT_CHANNEL_WIDTH_40MHZ : eHT_CHANNEL_WIDTH_20MHZ;
}
sap_config->acs_cfg.pri_ch_freq =
wlan_reg_chan_to_freq(hdd_ctx->pdev, channel_list->pri_ch);
sap_config->acs_cfg.pri_ch_freq = channel_list->pri_chan_freq;
sap_config->acs_cfg.ch_width = channel_list->chan_width;
sap_config->acs_cfg.vht_seg0_center_ch_freq =
wlan_reg_chan_to_freq(
hdd_ctx->pdev, channel_list->vht_seg0_center_ch);
channel_list->vht_seg0_center_chan_freq;
sap_config->acs_cfg.vht_seg1_center_ch_freq =
wlan_reg_chan_to_freq(
hdd_ctx->pdev, channel_list->vht_seg1_center_ch);
channel_list->vht_seg1_center_chan_freq;
sap_config->acs_cfg.ht_sec_ch_freq =
wlan_reg_chan_to_freq(hdd_ctx->pdev, channel_list->ht_sec_ch);
channel_list->ht_sec_chan_freq;
}
static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason,
@ -11080,6 +11189,7 @@ static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason,
struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
QDF_STATUS status = QDF_STATUS_SUCCESS;
mac_handle_t mac_handle;
uint32_t ch;
if (!channel_list) {
hdd_err("channel_list is NULL");
@ -11095,9 +11205,9 @@ static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason,
qdf_mc_timer_stop(&adapter->session.ap.vendor_acs_timer);
}
if (channel_list->pri_ch == 0) {
if (channel_list->pri_chan_freq == 0) {
/* Check mode, set default channel */
channel_list->pri_ch = 6;
channel_list->pri_chan_freq = 2437;
/*
* sap_select_default_oper_chan(mac_handle,
* sap_config->acs_cfg.hw_mode);
@ -11115,9 +11225,11 @@ static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason,
/* DFS detected on current channel */
case QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS:
ch = wlan_reg_freq_to_chan(hdd_ctx->pdev,
channel_list->pri_chan_freq);
wlan_sap_update_next_channel(
WLAN_HDD_GET_SAP_CTX_PTR(adapter),
channel_list->pri_ch,
WLAN_HDD_GET_SAP_CTX_PTR(adapter), (uint8_t)ch,
channel_list->chan_width);
status = sme_update_new_channel_event(
mac_handle,
@ -11126,15 +11238,15 @@ static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason,
/* LTE coex event on current channel */
case QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX:
sap_config->acs_cfg.pri_ch_freq =
wlan_reg_chan_to_freq(hdd_ctx->pdev,
channel_list->pri_ch);
ch = wlan_reg_freq_to_chan(hdd_ctx->pdev,
channel_list->pri_chan_freq);
sap_config->acs_cfg.pri_ch_freq = channel_list->pri_chan_freq;
sap_config->acs_cfg.ch_width = channel_list->chan_width;
hdd_ap_ctx->sap_config.ch_width_orig =
channel_list->chan_width;
wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->vdev_id,
CSA_REASON_LTE_COEX);
hdd_switch_sap_channel(adapter, channel_list->pri_ch, true);
hdd_switch_sap_channel(adapter, (uint8_t)ch, true);
break;
default:
@ -11159,12 +11271,24 @@ static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason,
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1
#define SET_CHAN_CHANNEL_WIDTH \
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
#define SET_CHAN_MAX QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX
#define SET_CHAN_FREQ_LIST QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST
#define SET_CHAN_FREQUENCY_PRIMARY \
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY
#define SET_CHAN_FREQUENCY_SECONDARY \
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY
#define SET_CHAN_SEG0_CENTER_FREQUENCY \
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0
#define SET_CHAN_SEG1_CENTER_FREQUENCY \
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1
#define SET_CHAN_MAX QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX
#define SET_EXT_ACS_BAND QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_BAND
static const struct nla_policy acs_chan_config_policy[SET_CHAN_MAX + 1] = {
[SET_CHAN_REASON] = {.type = NLA_U8},
[SET_CHAN_CHAN_LIST] = {.type = NLA_NESTED},
[SET_CHAN_FREQ_LIST] = {.type = NLA_NESTED},
};
static const struct nla_policy acs_chan_list_policy[SET_CHAN_MAX + 1] = {
@ -11174,21 +11298,29 @@ static const struct nla_policy acs_chan_list_policy[SET_CHAN_MAX + 1] = {
[SET_CHAN_SEG1_CENTER_CHANNEL] = {.type = NLA_U8},
[SET_CHAN_CHANNEL_WIDTH] = {.type = NLA_U8},
[SET_EXT_ACS_BAND] = {.type = NLA_U8},
[SET_CHAN_FREQUENCY_PRIMARY] = {.type = NLA_U32},
[SET_CHAN_FREQUENCY_SECONDARY] = {.type = NLA_U32},
[SET_CHAN_SEG0_CENTER_FREQUENCY] = {.type = NLA_U32},
[SET_CHAN_SEG1_CENTER_FREQUENCY] = {.type = NLA_U32},
};
/**
* hdd_parse_vendor_acs_chan_config() - API to parse vendor acs channel config
* @channel_list: pointer to hdd_vendor_chan_info
* @reason: channel change reason
* hdd_extract_external_acs_frequencies() - API to parse and extract vendor acs
* channel frequency (in MHz) configuration.
* @hdd_ctx: pointer to hdd context
* @list_ptr: pointer to hdd_vendor_chan_info
* @channel_cnt: channel count
* @data: data
* @data_len: data len
*
* Return: 0 on success, negative errno on failure
*/
static int hdd_parse_vendor_acs_chan_config(struct hdd_vendor_chan_info
**chan_list_ptr, uint8_t *reason, uint8_t *channel_cnt,
const void *data, int data_len)
static int
hdd_extract_external_acs_frequencies(struct hdd_context *hdd_ctx,
struct hdd_vendor_chan_info **list_ptr,
uint8_t *channel_cnt,
const void *data, int data_len)
{
int rem;
uint32_t i = 0;
@ -11203,32 +11335,120 @@ static int hdd_parse_vendor_acs_chan_config(struct hdd_vendor_chan_info
return -EINVAL;
}
if (tb[SET_CHAN_REASON])
*reason = nla_get_u8(tb[SET_CHAN_REASON]);
nla_for_each_nested(curr_attr, tb[SET_CHAN_FREQ_LIST], rem)
i++;
if (!tb[SET_CHAN_CHAN_LIST]) {
hdd_err("channel list empty");
if (!i) {
hdd_err_rl("Error: channel count is zero");
return -EINVAL;
}
if (i > NUM_CHANNELS) {
hdd_err_rl("Error: Exceeded max channels: %u", NUM_CHANNELS);
return -ENOMEM;
}
channel_list = qdf_mem_malloc(sizeof(struct hdd_vendor_chan_info) * i);
if (!channel_list)
return -ENOMEM;
*channel_cnt = (uint8_t)i;
i = 0;
nla_for_each_nested(curr_attr, tb[SET_CHAN_FREQ_LIST], rem) {
if (wlan_cfg80211_nla_parse_nested(tb2, SET_CHAN_MAX,
curr_attr,
acs_chan_list_policy)) {
hdd_err_rl("nla_parse failed");
qdf_mem_free(channel_list);
*channel_cnt = 0;
return -EINVAL;
}
if (tb2[SET_EXT_ACS_BAND])
channel_list[i].band =
nla_get_u8(tb2[SET_EXT_ACS_BAND]);
if (tb2[SET_CHAN_FREQUENCY_PRIMARY])
channel_list[i].pri_chan_freq =
nla_get_u32(tb2[SET_CHAN_FREQUENCY_PRIMARY]);
if (tb2[SET_CHAN_FREQUENCY_SECONDARY])
channel_list[i].ht_sec_chan_freq =
nla_get_u32(tb2[SET_CHAN_FREQUENCY_SECONDARY]);
if (tb2[SET_CHAN_SEG0_CENTER_FREQUENCY])
channel_list[i].vht_seg0_center_chan_freq =
nla_get_u32(tb2[SET_CHAN_SEG0_CENTER_FREQUENCY]);
if (tb2[SET_CHAN_SEG1_CENTER_FREQUENCY])
channel_list[i].vht_seg1_center_chan_freq =
nla_get_u32(tb2[SET_CHAN_SEG1_CENTER_FREQUENCY]);
if (tb2[SET_CHAN_CHANNEL_WIDTH])
channel_list[i].chan_width =
nla_get_u8(tb2[SET_CHAN_CHANNEL_WIDTH]);
hdd_debug("index %d, pri_chan_freq %u, ht_sec_chan_freq %u seg0_freq %u seg1_freq %u width %u",
i, channel_list[i].pri_chan_freq,
channel_list[i].ht_sec_chan_freq,
channel_list[i].vht_seg0_center_chan_freq,
channel_list[i].vht_seg1_center_chan_freq,
channel_list[i].chan_width);
i++;
}
*list_ptr = channel_list;
return 0;
}
/**
* hdd_extract_external_acs_channels() - API to parse and extract vendor acs
* channel configuration.
* @hdd_ctx: pointer to hdd context
* @list_ptr: pointer to hdd_vendor_chan_info
* @channel_cnt: channel count
* @data: data
* @data_len: data len
*
* Return: 0 on success, negative errno on failure
*/
static int
hdd_extract_external_acs_channels(struct hdd_context *hdd_ctx,
struct hdd_vendor_chan_info **list_ptr,
uint8_t *channel_cnt,
const void *data, int data_len)
{
int rem;
uint32_t i = 0;
struct nlattr *tb[SET_CHAN_MAX + 1];
struct nlattr *tb2[SET_CHAN_MAX + 1];
struct nlattr *curr_attr;
struct hdd_vendor_chan_info *channel_list;
if (wlan_cfg80211_nla_parse(tb, SET_CHAN_MAX, data, data_len,
acs_chan_config_policy)) {
hdd_err("Invalid ATTR");
return -EINVAL;
}
nla_for_each_nested(curr_attr, tb[SET_CHAN_CHAN_LIST], rem)
i++;
if (!i) {
hdd_err_rl("Error: channel count is zero");
return -EINVAL;
}
if (i > NUM_CHANNELS) {
hdd_err("Error: Exceeded max channels: %u", NUM_CHANNELS);
hdd_err_rl("Error: Exceeded max channels: %u", NUM_CHANNELS);
return -ENOMEM;
}
*channel_cnt = (uint8_t)i;
if (i == 0)
hdd_err("incorrect channel count");
channel_list = qdf_mem_malloc(sizeof(struct hdd_vendor_chan_info) *
(*channel_cnt));
channel_list = qdf_mem_malloc(sizeof(struct hdd_vendor_chan_info) * i);
if (!channel_list)
return -ENOMEM;
*channel_cnt = (uint8_t)i;
i = 0;
nla_for_each_nested(curr_attr, tb[SET_CHAN_CHAN_LIST], rem) {
if (wlan_cfg80211_nla_parse_nested(tb2, SET_CHAN_MAX,
@ -11236,47 +11456,119 @@ static int hdd_parse_vendor_acs_chan_config(struct hdd_vendor_chan_info
acs_chan_list_policy)) {
hdd_err("nla_parse failed");
qdf_mem_free(channel_list);
*channel_cnt = 0;
return -EINVAL;
}
if (tb2[SET_EXT_ACS_BAND]) {
channel_list[i].band =
nla_get_u8(tb2[SET_EXT_ACS_BAND]);
}
/* Parse and Fetch allowed SSID list*/
if (tb2[SET_CHAN_PRIMARY_CHANNEL]) {
channel_list[i].pri_ch =
nla_get_u8(
tb2[SET_CHAN_PRIMARY_CHANNEL]);
uint32_t ch =
nla_get_u8(tb2[SET_CHAN_PRIMARY_CHANNEL]);
channel_list[i].pri_chan_freq =
wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch);
}
if (tb2[SET_CHAN_SECONDARY_CHANNEL]) {
channel_list[i].ht_sec_ch =
uint32_t ch =
nla_get_u8(tb2[SET_CHAN_SECONDARY_CHANNEL]);
channel_list[i].ht_sec_chan_freq =
wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch);
}
if (tb2[SET_CHAN_SEG0_CENTER_CHANNEL]) {
channel_list[i].vht_seg0_center_ch =
uint32_t ch =
nla_get_u8(tb2[SET_CHAN_SEG0_CENTER_CHANNEL]);
channel_list[i].vht_seg0_center_chan_freq =
wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch);
}
if (tb2[SET_CHAN_SEG1_CENTER_CHANNEL]) {
channel_list[i].vht_seg1_center_ch =
uint32_t ch =
nla_get_u8(tb2[SET_CHAN_SEG1_CENTER_CHANNEL]);
channel_list[i].vht_seg1_center_chan_freq =
wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch);
}
if (tb2[SET_CHAN_CHANNEL_WIDTH]) {
channel_list[i].chan_width =
nla_get_u8(tb2[SET_CHAN_CHANNEL_WIDTH]);
}
hdd_debug("index %d pri %d sec %d seg0 %d seg1 %d width %d",
i, channel_list[i].pri_ch,
channel_list[i].ht_sec_ch,
channel_list[i].vht_seg0_center_ch,
channel_list[i].vht_seg1_center_ch,
channel_list[i].chan_width);
hdd_debug("index %d, pri_chan_freq %u, ht_sec_chan_freq %u seg0_freq %u seg1_freq %u width %u",
i, channel_list[i].pri_chan_freq,
channel_list[i].ht_sec_chan_freq,
channel_list[i].vht_seg0_center_chan_freq,
channel_list[i].vht_seg1_center_chan_freq,
channel_list[i].chan_width);
i++;
}
*chan_list_ptr = channel_list;
*list_ptr = channel_list;
return 0;
}
/**
* hdd_parse_vendor_acs_chan_config() - API to parse vendor acs channel config
* @hdd_ctx: pointer to hdd context
* @channel_list: pointer to hdd_vendor_chan_info
* @reason: channel change reason
* @channel_cnt: channel count
* @data: data
* @data_len: data len
*
* Return: 0 on success, negative errno on failure
*/
static int
hdd_parse_vendor_acs_chan_config(struct hdd_context *hdd_ctx,
struct hdd_vendor_chan_info **chan_list_ptr,
uint8_t *reason, uint8_t *channel_cnt,
const void *data, int data_len)
{
struct nlattr *tb[SET_CHAN_MAX + 1];
int ret;
if (wlan_cfg80211_nla_parse(tb, SET_CHAN_MAX, data, data_len,
acs_chan_config_policy)) {
hdd_err("Invalid ATTR");
return -EINVAL;
}
if (tb[SET_CHAN_REASON])
*reason = nla_get_u8(tb[SET_CHAN_REASON]);
if (!tb[SET_CHAN_FREQ_LIST] && !tb[SET_CHAN_CHAN_LIST]) {
hdd_err("Both channel list and frequency list are empty");
return -EINVAL;
}
if (tb[SET_CHAN_FREQ_LIST]) {
ret = hdd_extract_external_acs_frequencies(hdd_ctx,
chan_list_ptr,
channel_cnt,
data, data_len);
if (ret) {
hdd_err("Failed to extract frequencies");
return ret;
}
return 0;
}
ret = hdd_extract_external_acs_channels(hdd_ctx, chan_list_ptr,
channel_cnt, data, data_len);
if (ret)
hdd_err("Failed to extract channels");
return ret;
}
/**
* Undef short names for vendor set channel configuration
*/
@ -11286,6 +11578,13 @@ static int hdd_parse_vendor_acs_chan_config(struct hdd_vendor_chan_info
#undef SET_CHAN_SECONDARY_CHANNEL
#undef SET_CHAN_SEG0_CENTER_CHANNEL
#undef SET_CHAN_SEG1_CENTER_CHANNEL
#undef SET_CHAN_FREQ_LIST
#undef SET_CHAN_FREQUENCY_PRIMARY
#undef SET_CHAN_FREQUENCY_SECONDARY
#undef SET_CHAN_SEG0_CENTER_FREQUENCY
#undef SET_CHAN_SEG1_CENTER_FREQUENCY
#undef SET_CHAN_CHANNEL_WIDTH
#undef SET_CHAN_MAX
@ -11328,8 +11627,9 @@ static int __wlan_hdd_cfg80211_update_vendor_channel(struct wiphy *wiphy,
return -EINVAL;
}
ret_val = hdd_parse_vendor_acs_chan_config(&channel_list, &reason,
&channel_cnt, data, data_len);
ret_val = hdd_parse_vendor_acs_chan_config(hdd_ctx, &channel_list,
&reason, &channel_cnt, data,
data_len);
channel_list_ptr = channel_list;
if (ret_val)
return ret_val;
@ -11337,14 +11637,14 @@ static int __wlan_hdd_cfg80211_update_vendor_channel(struct wiphy *wiphy,
/* Validate channel to be set */
while (channel_cnt && channel_list) {
qdf_status = wlan_hdd_validate_acs_channel(adapter,
channel_list->pri_ch,
channel_list->pri_chan_freq,
channel_list->chan_width);
if (qdf_status == QDF_STATUS_SUCCESS)
break;
else if (channel_cnt == 1) {
hdd_err("invalid channel %d received from app",
channel_list->pri_ch);
channel_list->pri_ch = 0;
hdd_err("invalid channel frequ %u received from app",
channel_list->pri_chan_freq);
channel_list->pri_chan_freq = 0;
break;
}
@ -11359,7 +11659,8 @@ static int __wlan_hdd_cfg80211_update_vendor_channel(struct wiphy *wiphy,
return -EINVAL;
}
hdd_debug("received primary channel as %d", channel_list->pri_ch);
hdd_debug("received primary channel freq as %d",
channel_list->pri_chan_freq);
ret_val = hdd_update_acs_channel(adapter, reason,
channel_cnt, channel_list);