summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgaolez <gaolez@codeaurora.org>2017-01-09 14:21:32 +0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-02-13 17:37:11 -0800
commitbd80acddaef75f6a99bca41bdd579edc2fefa8e3 (patch)
treefc9e0aab23be30cdcbc42ad356e77ebdaadc0c01
parente85a05376e3c09a8f958295f07acce09e78715eb (diff)
qcacld-2.0: Support manual channel width switch to 5/10M
Allow user to trigger channel width switch to 5/10M via nl80211 NL80211_CMD_CHANNEL_SWITCH command. Change-Id: I19750b8411dc3d95cce7eb9b73c5614e1dc590f4 CRs-Fixed: 1108836
-rw-r--r--CORE/HDD/inc/wlan_hdd_cfg.h5
-rw-r--r--CORE/HDD/inc/wlan_hdd_hostapd.h17
-rw-r--r--CORE/HDD/src/wlan_hdd_cfg.c16
-rw-r--r--CORE/HDD/src/wlan_hdd_cfg80211.c129
-rw-r--r--CORE/HDD/src/wlan_hdd_hostapd.c210
-rw-r--r--CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c20
-rw-r--r--CORE/SAP/inc/sapApi.h19
-rw-r--r--CORE/SAP/src/sapModule.c9
8 files changed, 357 insertions, 68 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index 7355f128982e..d83b1cd8adb1 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -4333,6 +4333,7 @@ FG_BTC_BT_INTERVAL_PAGE_P2P_STA_DEFAULT
* g_sub20_channel_width=3: Switch between 5 and 20 MHz bandwidth dynamically
* g_sub20_channel_width=4: Switch between 10 and 20 MHz bandwidth dynamically
* g_sub20_channel_width=5: Switch between 5/10 and 20 MHz bandwidth dynamically
+ * g_sub20_channel_width=6: Switch between 5/10 and 20 MHz bandwidth manually
* Default : Disable
*/
#define CFG_SUB_20_CHANNEL_WIDTH_NAME "g_sub20_channel_width"
@@ -4342,8 +4343,10 @@ FG_BTC_BT_INTERVAL_PAGE_P2P_STA_DEFAULT
#define CFG_SUB_20_CHANNEL_WIDTH_DYN_5MHZ (3)
#define CFG_SUB_20_CHANNEL_WIDTH_DYN_10MHZ (4)
#define CFG_SUB_20_CHANNEL_WIDTH_DYN_ALL (5)
+#define CFG_SUB_20_CHANNEL_WIDTH_MANUAL (6)
+
#define CFG_SUB_20_CHANNEL_WIDTH_MIN (0)
-#define CFG_SUB_20_CHANNEL_WIDTH_MAX (5)
+#define CFG_SUB_20_CHANNEL_WIDTH_MAX (6)
#define CFG_SUB_20_CHANNEL_WIDTH_DEFAULT (0)
/*
diff --git a/CORE/HDD/inc/wlan_hdd_hostapd.h b/CORE/HDD/inc/wlan_hdd_hostapd.h
index bfc64a7a316f..07452cb67db1 100644
--- a/CORE/HDD/inc/wlan_hdd_hostapd.h
+++ b/CORE/HDD/inc/wlan_hdd_hostapd.h
@@ -228,6 +228,10 @@ bool hdd_hostapd_sub20_channelwidth_can_switch(
hdd_adapter_t *adapter, uint32_t *sub20_channel_width);
bool hdd_hostapd_sub20_channelwidth_can_restore(
hdd_adapter_t *adapter);
+bool hdd_hostapd_sub20_channelwidth_can_set(
+ hdd_adapter_t *adapter, uint32_t sub20_channel_width);
+int hdd_softap_set_channel_sub20_chanwidth_change(
+ struct net_device *dev, uint32_t chan_width);
#else
static inline bool hdd_hostapd_sub20_channelwidth_can_switch(
hdd_adapter_t *adapter, uint32_t *sub20_channel_width)
@@ -240,5 +244,18 @@ static inline bool hdd_hostapd_sub20_channelwidth_can_restore(
{
return false;
}
+
+static inline bool hdd_hostapd_sub20_channelwidth_can_set(
+ hdd_adapter_t *adapter, uint32_t sub20_channel_width)
+{
+ return false;
+}
+
+static inline
+int hdd_softap_set_channel_sub20_chanwidth_change(
+ struct net_device *dev, uint32_t chan_width)
+{
+ return -ENOTSUPP;
+}
#endif
#endif // end #if !defined( WLAN_HDD_HOSTAPD_H )
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index 03dac1b066b5..25475d14a458 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -6502,20 +6502,20 @@ eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode( eHddDot11Mode dot11Mode )
uint8_t hdd_cfg_get_sub20_dyn_capabilities(hdd_context_t *hdd_ctx_ptr)
{
hdd_config_t *config_ptr = hdd_ctx_ptr->cfg_ini;
+ uint8_t sub_20_channel_width = config_ptr->sub_20_channel_width;
- if (config_ptr->sub_20_channel_width ==
- CFG_SUB_20_CHANNEL_WIDTH_DYN_5MHZ) {
+ switch (sub_20_channel_width) {
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_5MHZ:
return SUB20_MODE_5MHZ;
- } else if (config_ptr->sub_20_channel_width ==
- CFG_SUB_20_CHANNEL_WIDTH_DYN_10MHZ) {
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_10MHZ:
return SUB20_MODE_10MHZ;
- } else if (config_ptr->sub_20_channel_width ==
- CFG_SUB_20_CHANNEL_WIDTH_DYN_ALL) {
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_ALL:
+ case CFG_SUB_20_CHANNEL_WIDTH_MANUAL:
return SUB20_MODE_5MHZ | SUB20_MODE_10MHZ;
+ default:
+ return SUB20_MODE_NONE;
}
- return SUB20_MODE_NONE;
}
-
/**
* hdd_cfg_get_static_sub20_channel_width()
* @hdd_ctx_ptr: HDD context
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 0a13285d4397..e21f502487ac 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -14314,6 +14314,10 @@ int wlan_hdd_cfg80211_init(struct device *dev,
#ifdef CHANNEL_SWITCH_SUPPORTED
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
#endif
+
+ if (pCfg->sub_20_channel_width)
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ;
+
wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0)) || \
@@ -15809,6 +15813,24 @@ static int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter,
pConfig->reduced_beacon_interval =
iniConfig->reduced_beacon_interval;
+ switch (iniConfig->sub_20_channel_width) {
+ case CFG_SUB_20_CHANNEL_WIDTH_DISABLE:
+ pConfig->sub20_switch_mode = SUB20_NONE;
+ break;
+ case CFG_SUB_20_CHANNEL_WIDTH_5MHZ:
+ case CFG_SUB_20_CHANNEL_WIDTH_10MHZ:
+ pConfig->sub20_switch_mode = SUB20_STATIC;
+ break;
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_5MHZ:
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_10MHZ:
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_ALL:
+ pConfig->sub20_switch_mode = SUB20_DYN;
+ break;
+ case CFG_SUB_20_CHANNEL_WIDTH_MANUAL:
+ pConfig->sub20_switch_mode = SUB20_MANUAL;
+ break;
+ }
+
//channel is already set in the set_channel Call back
//pConfig->channel = pCommitConfig->channel;
@@ -17057,50 +17079,56 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}
- if (sub20_config != CFG_SUB_20_CHANNEL_WIDTH_DYN_ALL) {
- sub20_channelwidth = (sub20_static_channelwidth != 0) ?
- sub20_static_channelwidth : sub20_dyn_channelwidth;
- phy_sub20_channel_width =
- (sub20_channelwidth == SUB20_MODE_5MHZ) ?
- CH_WIDTH_5MHZ : CH_WIDTH_10MHZ;
- channel_support_sub20 =
- vos_is_channel_support_sub20(channel,
- phy_sub20_channel_width,
- 0);
- if (!channel_support_sub20) {
- hddLog(VOS_TRACE_LEVEL_ERROR,
- FL("ch%dwidth%d unsupport by reg domain"),
- channel, phy_sub20_channel_width);
- return -EINVAL;
- }
- } else {
- channel_support_sub20 =
- vos_is_channel_support_sub20(channel,
- CH_WIDTH_5MHZ, 0);
- if (!channel_support_sub20) {
- hddLog(VOS_TRACE_LEVEL_ERROR,
- FL("ch%dwidth5M unsupport by reg domain"),
- channel);
- sub20_dyn_channelwidth &= ~SUB20_MODE_5MHZ;
- }
+ switch (sub20_config) {
+ case CFG_SUB_20_CHANNEL_WIDTH_5MHZ:
+ case CFG_SUB_20_CHANNEL_WIDTH_10MHZ:
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_5MHZ:
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_10MHZ:
+ sub20_channelwidth = (sub20_static_channelwidth != 0) ?
+ sub20_static_channelwidth : sub20_dyn_channelwidth;
+ phy_sub20_channel_width =
+ (sub20_channelwidth == SUB20_MODE_5MHZ) ?
+ CH_WIDTH_5MHZ : CH_WIDTH_10MHZ;
+ channel_support_sub20 =
+ vos_is_channel_support_sub20(channel,
+ phy_sub20_channel_width,
+ 0);
+ if (!channel_support_sub20) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("ch%dwidth%d unsupport by reg domain"),
+ channel, phy_sub20_channel_width);
+ return -EINVAL;
+ }
+ break;
+ case CFG_SUB_20_CHANNEL_WIDTH_DYN_ALL:
+ channel_support_sub20 =
+ vos_is_channel_support_sub20(channel, CH_WIDTH_5MHZ, 0);
+ if (!channel_support_sub20) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("ch%dwidth5M unsupport by reg domain"),
+ channel);
+ sub20_dyn_channelwidth &= ~SUB20_MODE_5MHZ;
+ }
- channel_support_sub20 =
- vos_is_channel_support_sub20(channel,
- CH_WIDTH_10MHZ, 0);
- if (!channel_support_sub20) {
- hddLog(VOS_TRACE_LEVEL_ERROR,
- FL("ch%dwidth10M unsupport by reg domain"),
- channel);
- sub20_dyn_channelwidth &= ~SUB20_MODE_10MHZ;
- }
+ channel_support_sub20 =
+ vos_is_channel_support_sub20(channel, CH_WIDTH_10MHZ, 0);
+ if (!channel_support_sub20) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("ch%dwidth10M unsupport by reg domain"),
+ channel);
+ sub20_dyn_channelwidth &= ~SUB20_MODE_10MHZ;
+ }
- if (sub20_dyn_channelwidth == 0) {
- return -EINVAL;
- } else {
- sme_config.sub20_dynamic_channelwidth =
+ if (sub20_dyn_channelwidth == 0) {
+ return -EINVAL;
+ } else {
+ sme_config.sub20_dynamic_channelwidth =
sub20_dyn_channelwidth;
- sme_UpdateConfig(pHddCtx->hHal, &sme_config);
- }
+ sme_UpdateConfig(pHddCtx->hHal, &sme_config);
+ }
+ break;
+ default:
+ break;
}
}
@@ -27852,11 +27880,18 @@ static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy,
hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
v_U8_t channel;
+ uint8_t current_channel;
v_U16_t freq;
int ret;
+ tsap_Config_t *sap_config;
- hddLog(LOG1, FL(" Set Freq %d"), csa_params->chandef.chan->center_freq);
+ hddLog(LOG1, FL("Set Freq %d sub20 chanwidth %d"),
+ csa_params->chandef.chan->center_freq,
+ csa_params->chandef.width);
+ current_channel =
+ (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operatingChannel;
+ sap_config = &((WLAN_HDD_GET_AP_CTX_PTR(adapter))->sapConfig);
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
ret = wlan_hdd_validate_context(hdd_ctx);
@@ -27871,7 +27906,15 @@ static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy,
freq = csa_params->chandef.chan->center_freq;
channel = vos_freq_to_chan(freq);
- ret = hdd_softap_set_channel_change(dev, channel);
+ if (channel != current_channel) {
+ ret = hdd_softap_set_channel_change(dev, channel);
+ } else if (sap_config->sub20_switch_mode == SUB20_MANUAL) {
+ ret = hdd_softap_set_channel_sub20_chanwidth_change(
+ dev, csa_params->chandef.width);
+ } else {
+ hddLog(LOGE, FL("nothing to do"));
+ return -EINVAL;
+ }
return ret;
}
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index 4358e404d0e8..f47ad1550e62 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -368,8 +368,9 @@ bool hdd_hostapd_sub20_channelwidth_can_switch(
int i;
int sta_count = 0;
uint8_t sap_s20_caps;
+ uint8_t sap_s20_config;
uint8_t sta_s20_caps = SUB20_MODE_NONE;
- tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
+ tHalHandle hal_ptr = WLAN_HDD_GET_HAL_CTX(adapter);
tSmeConfigParams *sme_config;
hdd_station_info_t *sta;
hdd_ap_ctx_t *ap = WLAN_HDD_GET_AP_CTX_PTR(adapter);
@@ -381,11 +382,13 @@ bool hdd_hostapd_sub20_channelwidth_can_switch(
}
vos_mem_zero(sme_config, sizeof(*sme_config));
- sme_GetConfigParam(hHal, sme_config);
+ sme_GetConfigParam(hal_ptr, sme_config);
sap_s20_caps = sme_config->sub20_dynamic_channelwidth;
+ sap_s20_config = sme_config->sub20_config_info;
vos_mem_free(sme_config);
- if (sap_s20_caps == SUB20_MODE_NONE) {
- hddLog(LOGE, FL("sub20 none"));
+ if (sap_s20_caps == SUB20_MODE_NONE ||
+ sap_s20_config == CFG_SUB_20_CHANNEL_WIDTH_MANUAL) {
+ hddLog(LOGE, FL("sub20 not switch"));
return false;
}
@@ -432,7 +435,7 @@ bool hdd_hostapd_sub20_channelwidth_can_restore(
int sta_count = 0;
uint8_t sap_s20_caps;
uint8_t sta_s20_caps = SUB20_MODE_NONE;
- tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter);
+ tHalHandle hal_ptr = WLAN_HDD_GET_HAL_CTX(adapter);
tSmeConfigParams *sme_config;
hdd_station_info_t *sta;
hdd_ap_ctx_t *ap = WLAN_HDD_GET_AP_CTX_PTR(adapter);
@@ -443,7 +446,7 @@ bool hdd_hostapd_sub20_channelwidth_can_restore(
return false;
}
vos_mem_zero(sme_config, sizeof(*sme_config));
- sme_GetConfigParam(hHal, sme_config);
+ sme_GetConfigParam(hal_ptr, sme_config);
sap_s20_caps = sme_config->sub20_dynamic_channelwidth;
vos_mem_free(sme_config);
@@ -471,6 +474,92 @@ bool hdd_hostapd_sub20_channelwidth_can_restore(
return true;
}
}
+
+/**
+ * hdd_hostapd_sub20_channelwidth_can_set() - check
+ * channel width manual switch to 5/10M condition
+ * @adapter: pointer to HDD context
+ * @sub20_channel_width: new channel width
+ *
+ * Return: true or false
+ */
+bool hdd_hostapd_sub20_channelwidth_can_set(
+ hdd_adapter_t *adapter, uint32_t sub20_channel_width)
+{
+ int i;
+ int sta_count = 0;
+ uint8_t sap_s20_config;
+ uint8_t sta_s20_caps = SUB20_MODE_NONE;
+ tHalHandle hal_ptr = WLAN_HDD_GET_HAL_CTX(adapter);
+ tSmeConfigParams *sme_config;
+ hdd_station_info_t *sta;
+ hdd_ap_ctx_t *ap = WLAN_HDD_GET_AP_CTX_PTR(adapter);
+ bool channel_support_sub20 = true;
+ enum phy_ch_width phy_sub20_channel_width = CH_WIDTH_INVALID;
+
+ sme_config = vos_mem_malloc(sizeof(*sme_config));
+ if (!sme_config) {
+ hddLog(LOGE, FL("mem alloc failed for sme_config"));
+ return false;
+ }
+ vos_mem_zero(sme_config, sizeof(*sme_config));
+
+ sme_GetConfigParam(hal_ptr, sme_config);
+ sap_s20_config = sme_config->sub20_config_info;
+ vos_mem_free(sme_config);
+ sme_config = NULL;
+ if (sap_s20_config != CFG_SUB_20_CHANNEL_WIDTH_MANUAL) {
+ hddLog(LOGE, FL("ini unsupport manual set sub20"));
+ return false;
+ }
+
+ switch (sub20_channel_width) {
+ case SUB20_MODE_5MHZ:
+ phy_sub20_channel_width = CH_WIDTH_5MHZ;
+ break;
+ case SUB20_MODE_10MHZ:
+ phy_sub20_channel_width = CH_WIDTH_10MHZ;
+ break;
+ case SUB20_MODE_NONE:
+ return true;
+ default:
+ return false;
+ }
+
+ channel_support_sub20 =
+ vos_is_channel_support_sub20(ap->operatingChannel,
+ phy_sub20_channel_width,
+ 0);
+ if (!channel_support_sub20) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("ch%d width%d unsupport by reg domain"),
+ ap->operatingChannel, phy_sub20_channel_width);
+ return false;
+ }
+
+ spin_lock_bh(&adapter->staInfo_lock);
+ for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
+ sta = &adapter->aStaInfo[i];
+ if (sta->isUsed && (ap->uBCStaId != i)) {
+ sta_count++;
+ sta_s20_caps |=
+ sta->sub20_dynamic_channelwidth;
+ }
+ }
+ spin_unlock_bh(&adapter->staInfo_lock);
+ if (sta_count != 1) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%d STAs connected with sub20 Channelwidth %d",
+ sta_count, sta_s20_caps);
+ return false;
+ }
+
+ if (!(sta_s20_caps & sub20_channel_width))
+ return false;
+
+ return true;
+}
+
#endif
/**
@@ -3023,6 +3112,115 @@ int hdd_softap_set_channel_change(struct net_device *dev, int target_channel)
return ret;
}
+#ifdef FEATURE_WLAN_SUB_20_MHZ
+/**
+ * hdd_softap_set_channel_sub20_chanwidth_change() -This
+ * function to support SAP channel change with CSA IE
+ * set in the beacons.
+ * @dev: Pointer to the net device
+ * @chan_width: new sub20 channel width
+ *
+ * Return: true or false
+ */
+int hdd_softap_set_channel_sub20_chanwidth_change(struct net_device *dev,
+ uint32_t chan_width)
+{
+ VOS_STATUS status;
+ int ret;
+ hdd_adapter_t *hostapd_adapter = (netdev_priv(dev));
+ hdd_context_t *hdd_ctx_ptr;
+ hdd_adapter_t *sta_adapter;
+ hdd_station_ctx_t *sta_ctx;
+ uint32_t sub20_chan_width;
+ bool sub20_operate_permission;
+ void *vos_ctx_ptr;
+
+ hdd_ctx_ptr = WLAN_HDD_GET_CTX(hostapd_adapter);
+ ret = wlan_hdd_validate_context(hdd_ctx_ptr);
+ if (ret)
+ return ret;
+
+ sta_adapter = hdd_get_adapter(hdd_ctx_ptr, WLAN_HDD_INFRA_STATION);
+ /*
+ * conc_custom_rule1:
+ * Force SCC for SAP + STA
+ * if STA is already connected then we shouldn't allow
+ * channel switch in SAP interface
+ */
+ if (sta_adapter && hdd_ctx_ptr->cfg_ini->conc_custom_rule1) {
+ sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter);
+ if (hdd_connIsConnected(sta_ctx)) {
+ hddLog(LOGE,
+ FL("sub20 chan switch not allowed"));
+ return -EBUSY;
+ }
+ }
+
+ switch (chan_width) {
+ case NL80211_CHAN_WIDTH_5:
+ sub20_chan_width = SUB20_MODE_5MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_10:
+ sub20_chan_width = SUB20_MODE_10MHZ;
+ break;
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ sub20_chan_width = SUB20_MODE_NONE;
+ break;
+ default:
+ hddLog(LOGE, FL("invalid param %d"), chan_width);
+ return -EINVAL;
+ }
+
+ sub20_operate_permission =
+ hdd_hostapd_sub20_channelwidth_can_set(hostapd_adapter,
+ sub20_chan_width);
+ if (!sub20_operate_permission) {
+ hddLog(LOGE, FL("can't set sub20_chan_width in curr chan"));
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&hdd_ctx_ptr->dfs_lock);
+ if (hdd_ctx_ptr->dfs_radar_found == VOS_TRUE) {
+ spin_unlock_bh(&hdd_ctx_ptr->dfs_lock);
+ hddLog(LOGE,
+ FL("sub20 chan width switch in progress!!"));
+ return -EBUSY;
+ }
+ /*
+ * Set the dfs_radar_found flag to mimic channel change
+ * when a radar is found. This will enable synchronizing
+ * SAP and HDD states similar to that of radar indication.
+ * Suspend the netif queues to stop queuing Tx frames
+ * from upper layers. netif queues will be resumed
+ * once the channel change is completed and SAP will
+ * post eSAP_START_BSS_EVENT success event to HDD.
+ */
+ hdd_ctx_ptr->dfs_radar_found = VOS_TRUE;
+ spin_unlock_bh(&hdd_ctx_ptr->dfs_lock);
+
+ vos_ctx_ptr = WLAN_HDD_GET_SAP_CTX_PTR(hostapd_adapter);
+ status = WLANSAP_set_sub20_channelwidth_with_csa(vos_ctx_ptr,
+ sub20_chan_width);
+ if (VOS_STATUS_SUCCESS != status) {
+ hddLog(LOGE,
+ FL("sub20 chan width %d switch failed"),
+ sub20_chan_width);
+ /*
+ * If channel change command fails then clear the
+ * radar found flag and also restart the netif
+ * queues.
+ */
+ spin_lock_bh(&hdd_ctx_ptr->dfs_lock);
+ hdd_ctx_ptr->dfs_radar_found = VOS_FALSE;
+ spin_unlock_bh(&hdd_ctx_ptr->dfs_lock);
+
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+#endif
+
/**
* hdd_sap_get_chan_width() - get channel width of sap
* @adapter: adapter being queried
diff --git a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
index 553ff7464533..2de24be84841 100644
--- a/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
+++ b/CORE/MAC/src/pe/lim/limProcessSmeReqMessages.c
@@ -7463,6 +7463,7 @@ limProcessSmeDfsCsaIeRequest(tpAniSirGlobal pMac, tANI_U32 *pMsg)
tpPESession psessionEntry = NULL;
tANI_U32 chanWidth = 0;
tANI_U8 sessionId;
+ uint8_t target_channel;
if ( pMsg == NULL )
{
@@ -7487,11 +7488,12 @@ limProcessSmeDfsCsaIeRequest(tpAniSirGlobal pMac, tANI_U32 *pMsg)
return;
}
+ target_channel = pDfsCsaIeRequest->targetChannel;
+
if ( psessionEntry )
{
/* target channel */
- psessionEntry->gLimChannelSwitch.primaryChannel =
- pDfsCsaIeRequest->targetChannel;
+ psessionEntry->gLimChannelSwitch.primaryChannel = target_channel;
/* Channel switch announcement needs to be included in beacon */
psessionEntry->dfsIncludeChanSwIe = VOS_TRUE;
@@ -7577,10 +7579,10 @@ limProcessSmeDfsCsaIeRequest(tpAniSirGlobal pMac, tANI_U32 *pMsg)
* Fetch the center channel based on the channel width
*/
psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0 =
- limGetCenterChannel(pMac,
- pDfsCsaIeRequest->targetChannel,
- psessionEntry->htSecondaryChannelOffset,
- psessionEntry->gLimWiderBWChannelSwitch.newChanWidth);
+ limGetCenterChannel(
+ pMac, target_channel,
+ psessionEntry->htSecondaryChannelOffset,
+ psessionEntry->gLimWiderBWChannelSwitch.newChanWidth);
/*
* This is not applicable for 20/40/80 Mhz.
* Only used when we support 80+80 Mhz
@@ -7609,9 +7611,11 @@ limProcessSmeDfsCsaIeRequest(tpAniSirGlobal pMac, tANI_U32 *pMsg)
psessionEntry->gLimChannelSwitch.switchCount );
/**
* Send Action frame after updating the beacon
- * Action frame is not required for sub 20 channel width changing
+ * Action frame is not required for dynamical sub20 channel
+ * width change
*/
- if (pDfsCsaIeRequest->sub20_channelwidth == 0) {
+ if (pDfsCsaIeRequest->sub20_channelwidth == 0 ||
+ psessionEntry->currentOperChannel != target_channel) {
if (CHAN_HOP_ALL_BANDS_ENABLE)
lim_send_chan_switch_action_frame
(pMac, psessionEntry->gLimChannelSwitch.primaryChannel,
diff --git a/CORE/SAP/inc/sapApi.h b/CORE/SAP/inc/sapApi.h
index bb98cab4bc02..4208fa0a757e 100644
--- a/CORE/SAP/inc/sapApi.h
+++ b/CORE/SAP/inc/sapApi.h
@@ -512,6 +512,24 @@ enum vendor_ie_access_policy {
ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT,
};
+/*
+ * enum sub20_chan_switch_mode- sub20 channel
+ * switch mode
+ * @SUB20_NONE: unsupport sub20 channel width
+ * @SUB20_STATIC: support sub20 channel width,
+ * but unsupport sub20 channel width switch
+ * @SUB20_DYN: support sub20 channel width,
+ * sub20 channel width switch auto
+ * @SUB20_MANUAL: support sub20 channel width,
+ * sub20 channel width switch manual
+ */
+enum sub20_chan_switch_mode {
+ SUB20_NONE,
+ SUB20_STATIC,
+ SUB20_DYN,
+ SUB20_MANUAL
+};
+
typedef struct sap_Config {
tSap_SSIDInfo_t SSIDinfo;
eCsrPhyMode SapHw_mode; /* Wireless Mode */
@@ -592,6 +610,7 @@ typedef struct sap_Config {
uint8_t sap_chanswitch_mode;
bool dfs_beacon_tx_enhanced;
uint16_t reduced_beacon_interval;
+ enum sub20_chan_switch_mode sub20_switch_mode;
} tsap_Config_t;
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
diff --git a/CORE/SAP/src/sapModule.c b/CORE/SAP/src/sapModule.c
index c1e9a9ac496a..6efbc9777582 100644
--- a/CORE/SAP/src/sapModule.c
+++ b/CORE/SAP/src/sapModule.c
@@ -830,6 +830,9 @@ WLANSAP_StartBss
pConfig->dfs_beacon_tx_enhanced;
pmac->sap.SapDfsInfo.reduced_beacon_interval =
pConfig->reduced_beacon_interval;
+ if (pConfig->sub20_switch_mode == SUB20_STATIC)
+ pmac->sap.SapDfsInfo.new_sub20_channelwidth =
+ pmac->sub20_channelwidth;
// Copy MAC filtering settings to sap context
pSapCtx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl;
vos_mem_copy(pSapCtx->acceptMacList, pConfig->accept_mac, sizeof(pConfig->accept_mac));
@@ -1852,8 +1855,10 @@ WLANSAP_set_sub20_channelwidth_with_csa(void *vos_ctx_ptr, uint32_t chan_width)
} else {
VOS_TRACE(VOS_MODULE_ID_SAP,
VOS_TRACE_LEVEL_ERROR,
- "%s: SAP is not in eSAP_STARTED state",
- __func__);
+ "%s: orgl chan_width=%d new chan_width=%d",
+ __func__,
+ sap_context_ptr->sub20_channelwidth,
+ chan_width);
return VOS_STATUS_E_FAULT;
}