diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c index 0aec412d278c..2bc63b28ed29 100644 --- a/os_if/linux/scan/src/wlan_cfg80211_scan.c +++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c @@ -34,6 +34,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) static uint32_t hdd_config_sched_scan_start_delay( @@ -945,10 +946,35 @@ int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, if (request->n_channels) { char chl[(request->n_channels * 5) + 1]; int len = 0; + bool ap_or_go_present = + policy_mgr_mode_specific_connection_count( + psoc, QDF_SAP_MODE, NULL) || + policy_mgr_mode_specific_connection_count( + psoc, QDF_P2P_GO_MODE, NULL); + for (i = 0; i < request->n_channels; i++) { channel = request->channels[i]->hw_value; if (wlan_is_dsrc_channel(wlan_chan_to_freq(channel))) continue; + + if (ap_or_go_present) { + bool ok; + int ret; + + ret = policy_mgr_is_chan_ok_for_dnbs(psoc, + channel, + &ok); + + if (QDF_IS_STATUS_ERROR(ret)) { + cfg80211_err("DNBS check failed"); + qdf_mem_free(req); + status = -EINVAL; + goto end; + } + if (!ok) + continue; + } + len += snprintf(chl + len, 5, "%d ", channel); req->scan_req.chan_list[i] = wlan_chan_to_freq(channel); num_chan++; @@ -1296,4 +1322,3 @@ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, frame_len, rssi, GFP_KERNEL); qdf_mem_free(mgmt); } - diff --git a/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h b/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h index fd618266564f..783bf78d165d 100644 --- a/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h +++ b/umac/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h @@ -1845,4 +1845,18 @@ void policy_mgr_update_old_hw_mode_index(struct wlan_objmgr_psoc *psoc, */ void policy_mgr_update_new_hw_mode_index(struct wlan_objmgr_psoc *psoc, uint32_t new_hw_mode_index); + +/** + * policy_mgr_is_chan_ok_for_dnbs() - Function to check if a channel + * is OK for "Do Not Break Stream" + * @psoc: PSOC object information + * @channel: Channel to check. + * @ok: Pointer to flag in which status will be stored + * This function checks if a channel is OK for + * "Do Not Break Stream" + * Return: SUCCESS or FAILURE + */ +QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc, + uint8_t channel, bool *ok); + #endif /* __WLAN_POLICY_MGR_API_H */ diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c index 380dae5a07d7..9c2f9054e491 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c @@ -39,6 +39,8 @@ #include "qdf_types.h" #include "qdf_trace.h" #include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" /* invalid channel id. */ #define INVALID_CHANNEL_ID 0 @@ -1355,9 +1357,11 @@ bool policy_mgr_is_ibss_conn_exist(struct wlan_objmgr_psoc *psoc, return status; } -bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc, - uint8_t *channel, uint8_t *vdev_id) +bool policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc, + uint8_t *channel, uint8_t *vdev_id, + enum policy_mgr_con_mode mode) { + uint32_t count, index = 0; uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; bool status = false; @@ -1374,10 +1378,10 @@ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc, } count = policy_mgr_mode_specific_connection_count( - psoc, PM_SAP_MODE, list); + psoc, mode, list); qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); if (count == 0) { - policy_mgr_err("No SAP connection"); + policy_mgr_err("No mode:[%d] connection", mode); status = false; } else if (count == 1) { *channel = pm_conc_connection_list[list[index]].chan; @@ -1393,7 +1397,8 @@ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc, *channel = pm_conc_connection_list[list[index]].chan; *vdev_id = pm_conc_connection_list[list[index]].vdev_id; - policy_mgr_notice("Multiple SAP connections, picking first one"); + policy_mgr_notice("Multiple mode:[%d] connections, picking first one", + mode); status = true; } qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); @@ -1401,6 +1406,15 @@ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc, return status; } +bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc, + uint8_t *channel, uint8_t *vdev_id) +{ + return policy_mgr_get_mode_specific_conn_info(psoc, + channel, + vdev_id, + PM_SAP_MODE); +} + bool policy_mgr_max_concurrent_connections_reached( struct wlan_objmgr_psoc *psoc) { @@ -2358,3 +2372,66 @@ bool policy_mgr_is_hw_mode_change_after_vdev_up(struct wlan_objmgr_psoc *psoc) return flag; } + +bool policy_mgr_vdev_mlme_is_dnsc_set(struct wlan_objmgr_vdev *vdev) +{ + /* TODO : Check Dont_Switch_Channel status from vdev mlme caps*/ + return false; +} + +QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc, + uint8_t channel, bool *ok) +{ + uint8_t operating_channel = 0, vdev_id = 0; + struct wlan_objmgr_vdev *vdev; + + if (!channel || !ok) { + policy_mgr_err("Invalid parameter"); + return QDF_STATUS_E_INVAL; + } + + if (policy_mgr_get_mode_specific_conn_info(psoc, + &operating_channel, + &vdev_id, + PM_SAP_MODE)) + policy_mgr_debug("SAP mode active"); + else if (policy_mgr_get_mode_specific_conn_info(psoc, + &operating_channel, + &vdev_id, + PM_P2P_GO_MODE)) + policy_mgr_debug("P2P_GO_MODE mode active"); + else { + *ok = true; + return QDF_STATUS_SUCCESS; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + /** + * If channel passed is same as AP/GO operating channel, then + * return true. + * If channel is different from operating channel but in same band. + * return false. + * If operating channel in different band. + * return true. + */ + /* TODO: To be enhanced for SBS */ + if (policy_mgr_vdev_mlme_is_dnsc_set(vdev)) { + if (operating_channel == channel) + *ok = true; + else if (WLAN_REG_IS_SAME_BAND_CHANNELS(operating_channel, + channel)) + *ok = false; + else + *ok = true; + } else { + *ok = true; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return QDF_STATUS_SUCCESS; +} diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h index 8dd4e4ddb457..9a48a16fc32e 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h @@ -398,4 +398,32 @@ QDF_STATUS policy_mgr_reset_sap_mandatory_channels( */ bool policy_mgr_get_sap_conn_info(struct wlan_objmgr_psoc *psoc, uint8_t *channel, uint8_t *vdev_id); + +/** + * policy_mgr_get_mode_specific_conn_info() - Get active mode specific + * channel and vdev id + * @psoc: PSOC object information + * @channel: Mode specific channel + * @vdev_id: Mode specific vdev id + * @mode: Connection Mode + * + * Get active mode specific channel and vdev id + * + * Return: true for success, else false + */ +bool policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc, + uint8_t *channel, uint8_t *vdev_id, + enum policy_mgr_con_mode mode); + +/** + * policy_mgr_vdev_mlme_is_dnsc_set - Check if user has set + * "Do_Not_Switch_Channel" for this vdev + * @vdev: vdev pointer + * + * Get "Do_Not_Switch_Channel" setting for this vdev + * + * Return: true for success, else false + */ +bool policy_mgr_vdev_mlme_is_dnsc_set(struct wlan_objmgr_vdev *vdev); + #endif diff --git a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c index 364bced7357d..88f35b2ad34e 100644 --- a/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c +++ b/umac/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c @@ -166,6 +166,41 @@ static QDF_STATUS policy_mgr_modify_pcl_based_on_enabled_channels( return QDF_STATUS_SUCCESS; } +static QDF_STATUS policy_mgr_modify_pcl_based_on_dnbs( + struct wlan_objmgr_psoc *psoc, + uint8_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + uint32_t i, pcl_len = 0; + uint8_t pcl_list[QDF_MAX_NUM_CHAN]; + uint8_t weight_list[QDF_MAX_NUM_CHAN]; + bool ok; + int ret; + + for (i = 0; i < *pcl_len_org; i++) { + ret = policy_mgr_is_chan_ok_for_dnbs(psoc, pcl_list_org[i], + &ok); + + if (QDF_IS_STATUS_ERROR(ret)) { + policy_mgr_err("Not able to check DNBS eligibility"); + return ret; + } + if (ok) { + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + } + + qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org)); + qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org)); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + uint8_t policy_mgr_get_channel(struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, uint32_t *vdev_id) { @@ -333,6 +368,13 @@ QDF_STATUS policy_mgr_get_pcl(struct wlan_objmgr_psoc *psoc, pcl_channels[i], pcl_weight[i]); } + status = policy_mgr_modify_pcl_based_on_dnbs(psoc, pcl_channels, + pcl_weight, len); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get modified pcl based on DNBS"); + return status; + } return QDF_STATUS_SUCCESS; }