summaryrefslogtreecommitdiff
path: root/umac
diff options
context:
space:
mode:
authorPaul Zhang <paulz@codeaurora.org>2018-02-02 17:43:37 +0800
committersnandini <snandini@codeaurora.org>2018-02-08 21:37:37 -0800
commitca6152167b9744d62723f49e6436a30c9366cb1d (patch)
tree5c36bcbfbba4fe58743c6d2902a9281ecbe29cc9 /umac
parente6d32a9f381fba48ec49fd5c703c76a4c3c7f453 (diff)
downloadqca-wfi-host-cmn-ca6152167b9744d62723f49e6436a30c9366cb1d.tar.gz
qcacmn: Support 11d for non-offload platform
Support 11d for non-offload platform by maintaining count of beacons encountered for each country code and choosing country code with max votes as device's country code. Change-Id: I83b66e980854eded17e254386561fa32b1f8c4ac CRs-Fixed: 2154048
Diffstat (limited to 'umac')
-rw-r--r--umac/regulatory/core/src/reg_services.c94
-rw-r--r--umac/regulatory/core/src/reg_services.h33
-rw-r--r--umac/regulatory/dispatcher/inc/wlan_reg_services_api.h36
-rw-r--r--umac/regulatory/dispatcher/src/wlan_reg_services_api.c21
-rw-r--r--umac/scan/core/src/wlan_scan_11d.c354
-rw-r--r--umac/scan/core/src/wlan_scan_11d.h95
-rw-r--r--umac/scan/core/src/wlan_scan_cache_db.c5
-rw-r--r--umac/scan/core/src/wlan_scan_filter.c5
-rw-r--r--umac/scan/core/src/wlan_scan_main.h3
-rw-r--r--umac/scan/core/src/wlan_scan_manager.c2
-rw-r--r--umac/scan/dispatcher/inc/wlan_scan_utils_api.h14
-rw-r--r--umac/scan/dispatcher/src/wlan_scan_ucfg_api.c4
12 files changed, 652 insertions, 14 deletions
diff --git a/umac/regulatory/core/src/reg_services.c b/umac/regulatory/core/src/reg_services.c
index 17578f4c2..257eb8b21 100644
--- a/umac/regulatory/core/src/reg_services.c
+++ b/umac/regulatory/core/src/reg_services.c
@@ -843,7 +843,8 @@ QDF_STATUS reg_get_channel_list_with_power(struct wlan_objmgr_pdev *pdev,
reg_channels = pdev_priv_obj->cur_chan_list;
for (i = 0, count = 0; i < NUM_CHANNELS; i++) {
- if (reg_channels[i].state) {
+ if (reg_channels[i].state &&
+ reg_channels[i].state != REGULATORY_CHAN_DISABLED) {
ch_list[count].chan_num =
reg_channels[i].chan_num;
ch_list[count++].tx_power =
@@ -1376,6 +1377,22 @@ QDF_STATUS reg_set_default_country(struct wlan_objmgr_psoc *psoc,
return QDF_STATUS_SUCCESS;
}
+bool reg_is_world_alpha2(uint8_t *alpha2)
+{
+ if ((alpha2[0] == '0') && (alpha2[1] == '0'))
+ return true;
+
+ return false;
+}
+
+bool reg_is_us_alpha2(uint8_t *alpha2)
+{
+ if ((alpha2[0] == 'U') && (alpha2[1] == 'S'))
+ return true;
+
+ return false;
+}
+
QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev,
uint8_t *country)
{
@@ -1430,6 +1447,55 @@ QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev,
return QDF_STATUS_SUCCESS;
}
+QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev,
+ uint8_t *country)
+{
+ struct wlan_regulatory_psoc_priv_obj *psoc_reg;
+ struct set_country country_code;
+ struct wlan_objmgr_psoc *psoc;
+ struct cc_regdmn_s rd;
+ QDF_STATUS status;
+
+ if (!country) {
+ reg_err("country code is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ psoc_reg = reg_get_psoc_obj(psoc);
+ if (!IS_VALID_PSOC_REG_OBJ(psoc_reg)) {
+ reg_err("psoc reg component is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (!qdf_mem_cmp(psoc_reg->cur_country,
+ country, REG_ALPHA2_LEN)) {
+ reg_debug("country is not different");
+ return QDF_STATUS_SUCCESS;
+ }
+
+ reg_info("programming new 11d country:%c%c to firmware",
+ country[0], country[1]);
+
+ qdf_mem_copy(country_code.country,
+ country, REG_ALPHA2_LEN + 1);
+ country_code.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+
+ psoc_reg->new_11d_ctry_pending = true;
+
+ if (psoc_reg->offload_enabled) {
+ reg_err("reg offload, 11d offload too!");
+ status = QDF_STATUS_E_FAULT;
+ } else {
+ qdf_mem_copy(rd.cc.alpha, country, REG_ALPHA2_LEN + 1);
+ rd.flags = ALPHA_IS_SET;
+ reg_program_chan_list(pdev, &rd);
+ status = QDF_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
QDF_STATUS reg_reset_country(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_reg;
@@ -1864,9 +1930,16 @@ static void reg_populate_band_channels(enum channel_enum start_chan,
if (found_rule_ptr) {
mas_chan_list[chan_enum].max_bw = bw;
-
reg_fill_channel_info(chan_enum, found_rule_ptr,
mas_chan_list, min_bw);
+ /* Disable 2.4 Ghz channels that dont have 20 mhz bw */
+ if (start_chan == MIN_24GHZ_CHANNEL &&
+ 20 > mas_chan_list[chan_enum].max_bw) {
+ mas_chan_list[chan_enum].chan_flags |=
+ REGULATORY_CHAN_DISABLED;
+ mas_chan_list[chan_enum].state =
+ REGULATORY_CHAN_DISABLED;
+ }
}
}
}
@@ -3967,6 +4040,23 @@ QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc,
return QDF_STATUS_SUCCESS;
}
+bool reg_11d_original_enabled_on_host(struct wlan_objmgr_psoc *psoc)
+{
+ struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+
+ psoc_priv_obj =
+ wlan_objmgr_psoc_get_comp_private_obj(psoc,
+ WLAN_UMAC_COMP_REGULATORY);
+
+ if (NULL == psoc_priv_obj) {
+ reg_err("reg psoc private obj is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return (psoc_priv_obj->enable_11d_supp_original &&
+ !psoc_priv_obj->is_11d_offloaded);
+}
+
bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc)
{
struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
diff --git a/umac/regulatory/core/src/reg_services.h b/umac/regulatory/core/src/reg_services.h
index 3ac25c1e4..afa867b8f 100644
--- a/umac/regulatory/core/src/reg_services.h
+++ b/umac/regulatory/core/src/reg_services.h
@@ -165,6 +165,22 @@ QDF_STATUS reg_set_default_country(struct wlan_objmgr_psoc *psoc,
uint8_t *country);
/**
+ * reg_is_world_alpha2 - is reg world mode
+ * @alpha2: country code pointer
+ *
+ * Return: true or false
+ */
+bool reg_is_world_alpha2(uint8_t *alpha2);
+
+/**
+ * reg_is_us_alpha2 - is US country code
+ * @alpha2: country code pointer
+ *
+ * Return: true or false
+ */
+bool reg_is_us_alpha2(uint8_t *alpha2);
+
+/**
* reg_set_country() - Set the current regulatory country
* @pdev: pdev device for country information
* @country: country value
@@ -174,6 +190,15 @@ QDF_STATUS reg_set_default_country(struct wlan_objmgr_psoc *psoc,
QDF_STATUS reg_set_country(struct wlan_objmgr_pdev *pdev, uint8_t *country);
/**
+ * reg_set_11d_country() - Set the 11d regulatory country
+ * @pdev: pdev device for country information
+ * @country: country value
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS reg_set_11d_country(struct wlan_objmgr_pdev *pdev, uint8_t *country);
+
+/**
* reg_reset_country() - Reset the regulatory country to default
* @psoc: The physical SoC to reset country for
*
@@ -337,6 +362,14 @@ QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc,
uint8_t *country);
/**
+ * reg_11d_original_enabled_on_host() - whether 11d original enabled on host
+ * @psoc: psoc ptr
+ *
+ * Return: bool
+ */
+bool reg_11d_original_enabled_on_host(struct wlan_objmgr_psoc *psoc);
+
+/**
* reg_11d_enabled_on_host() - know whether 11d enabled on host
* @psoc: psoc ptr
*
diff --git a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h
index f80edbc36..e5dcd3bd6 100644
--- a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h
+++ b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h
@@ -372,6 +372,21 @@ uint32_t wlan_reg_freq_to_chan(struct wlan_objmgr_pdev *pdev,
*/
uint32_t wlan_reg_chan_to_freq(struct wlan_objmgr_pdev *pdev,
uint32_t chan);
+/**
+ * wlan_reg_is_world() - reg is world mode
+ * @country: The country information
+ *
+ * Return: true or false
+ */
+bool wlan_reg_is_world(uint8_t *country);
+
+/**
+ * wlan_reg_is_us() - reg is us country
+ * @country: The country information
+ *
+ * Return: true or false
+ */
+bool wlan_reg_is_us(uint8_t *country);
/**
* wlan_reg_set_country() - Set the current regulatory country
@@ -381,7 +396,17 @@ uint32_t wlan_reg_chan_to_freq(struct wlan_objmgr_pdev *pdev,
* Return: QDF_STATUS
*/
QDF_STATUS wlan_reg_set_country(struct wlan_objmgr_pdev *pdev,
- uint8_t *country);
+ uint8_t *country);
+
+/**
+ * wlan_reg_set_11d_country() - Set the 11d regulatory country
+ * @pdev: The physical dev to set current country for
+ * @country: The country information to configure
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_reg_set_11d_country(struct wlan_objmgr_pdev *pdev,
+ uint8_t *country);
/**
* wlan_reg_register_chan_change_callback () - add chan change cbk
@@ -404,6 +429,15 @@ void wlan_reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc,
*/
void wlan_reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
reg_chan_change_callback cbk);
+
+/**
+ * wlan_reg_11d_original_enabled_on_host() - 11d original enabled don host
+ * @psoc: psoc ptr
+ *
+ * Return: bool
+ */
+bool wlan_reg_11d_original_enabled_on_host(struct wlan_objmgr_psoc *psoc);
+
/**
* wlan_reg_11d_enabled_on_host() - 11d enabled don host
* @psoc: psoc ptr
diff --git a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c
index 6005c0142..a211f49af 100644
--- a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c
+++ b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c
@@ -451,6 +451,22 @@ QDF_STATUS wlan_reg_set_country(struct wlan_objmgr_pdev *pdev,
return reg_set_country(pdev, country);
}
+QDF_STATUS wlan_reg_set_11d_country(struct wlan_objmgr_pdev *pdev,
+ uint8_t *country)
+{
+ return reg_set_11d_country(pdev, country);
+}
+
+bool wlan_reg_is_world(uint8_t *country)
+{
+ return reg_is_world_alpha2(country);
+}
+
+bool wlan_reg_is_us(uint8_t *country)
+{
+ return reg_is_us_alpha2(country);
+}
+
void wlan_reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc,
reg_chan_change_callback cbk,
void *arg)
@@ -465,6 +481,11 @@ void wlan_reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
reg_unregister_chan_change_callback(psoc, cbk);
}
+bool wlan_reg_11d_original_enabled_on_host(struct wlan_objmgr_psoc *psoc)
+{
+ return reg_11d_original_enabled_on_host(psoc);
+}
+
bool wlan_reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc)
{
return reg_11d_enabled_on_host(psoc);
diff --git a/umac/scan/core/src/wlan_scan_11d.c b/umac/scan/core/src/wlan_scan_11d.c
new file mode 100644
index 000000000..ecaba1295
--- /dev/null
+++ b/umac/scan/core/src/wlan_scan_11d.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains scan 11d api and functionality
+ */
+#include <qdf_status.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_scan_public_structs.h>
+#include <wlan_scan_utils_api.h>
+#include "wlan_scan_main.h"
+#include "wlan_scan_11d.h"
+#include "wlan_reg_services_api.h"
+#include "wlan_reg_ucfg_api.h"
+
+/**
+ * wlan_pdevid_get_cc_db() - private API to get cc db from pdev id
+ * @psoc: psoc object
+ * @pdev_id: pdev id
+ *
+ * Return: cc db for the pdev id
+ */
+static struct scan_country_code_db *
+wlan_pdevid_get_cc_db(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id)
+{
+ struct wlan_scan_obj *scan_obj;
+
+ if (pdev_id > WLAN_UMAC_MAX_PDEVS) {
+ scm_err("invalid pdev_id %d", pdev_id);
+ return NULL;
+ }
+
+ scan_obj = wlan_psoc_get_scan_obj(psoc);
+ if (!scan_obj)
+ return NULL;
+
+ return &scan_obj->cc_db[pdev_id];
+}
+
+/**
+ * wlan_pdev_get_cc_db() - private API to get cc db from pdev
+ * @psoc: psoc object
+ * @pdev: Pdev object
+ *
+ * Return: cc db for the pdev
+ */
+static struct scan_country_code_db *
+wlan_pdev_get_cc_db(struct wlan_objmgr_psoc *psoc,
+ struct wlan_objmgr_pdev *pdev)
+{
+ uint8_t pdev_id;
+
+ if (!pdev) {
+ scm_err("pdev is NULL");
+ return NULL;
+ }
+ pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+
+ return wlan_pdevid_get_cc_db(psoc, pdev_id);
+}
+
+/**
+ * scm_11d_elected_country_algo_fcc - private api to get cc per fcc algo
+ * @cc_db: scan country code db
+ *
+ * Return: true or false
+ */
+static bool
+scm_11d_elected_country_algo_fcc(struct scan_country_code_db *cc_db)
+{
+ uint8_t i;
+ uint8_t country_idx;
+ uint16_t max_votes;
+ bool found = false;
+
+ if (!cc_db->num_country_codes) {
+ scm_err("No AP with 11d Country code is present in scan list");
+ return false;
+ }
+
+ max_votes = cc_db->votes[0].votes;
+ if (wlan_reg_is_us(cc_db->votes[0].cc)) {
+ found = true;
+ country_idx = 0;
+ goto algo_done;
+ } else if (max_votes >= MIN_11D_AP_COUNT) {
+ found = true;
+ country_idx = 0;
+ }
+
+ for (i = 1; i < cc_db->num_country_codes; i++) {
+ if (wlan_reg_is_us(cc_db->votes[i].cc)) {
+ found = true;
+ country_idx = i;
+ goto algo_done;
+ }
+
+ if ((max_votes < cc_db->votes[i].votes) &&
+ (cc_db->votes[i].votes >= MIN_11D_AP_COUNT)) {
+ scm_debug("Votes for Country %c%c : %d",
+ cc_db->votes[i].cc[0],
+ cc_db->votes[i].cc[1],
+ cc_db->votes[i].votes);
+ max_votes = cc_db->votes[i].votes;
+ country_idx = i;
+ found = true;
+ }
+ }
+
+algo_done:
+ if (found) {
+ qdf_mem_copy(cc_db->elected_cc,
+ cc_db->votes[country_idx].cc,
+ REG_ALPHA2_LEN + 1);
+
+ scm_debug("Selected Country is %c%c With count %d",
+ cc_db->votes[country_idx].cc[0],
+ cc_db->votes[country_idx].cc[1],
+ cc_db->votes[country_idx].votes);
+ }
+
+ return found;
+}
+
+/**
+ * scm_11d_elected_country_info - private api to get cc
+ * @cc_db: scan country code db
+ *
+ * Return: true or false
+ */
+static bool
+scm_11d_elected_country_info(struct scan_country_code_db *cc_db)
+{
+ uint8_t i, j = 0;
+ uint8_t max_votes;
+
+ if (!cc_db->num_country_codes) {
+ scm_err("No AP with 11d Country code is present in scan list");
+ return false;
+ }
+
+ max_votes = cc_db->votes[0].votes;
+
+ for (i = 1; i < cc_db->num_country_codes; i++) {
+ /*
+ * If we have a tie for max votes for 2 different country codes,
+ * pick random.
+ */
+ if (max_votes < cc_db->votes[i].votes) {
+ scm_debug("Votes for Country %c%c : %d",
+ cc_db->votes[i].cc[0],
+ cc_db->votes[i].cc[1],
+ cc_db->votes[i].votes);
+
+ max_votes = cc_db->votes[i].votes;
+ j = i;
+ }
+ }
+
+ qdf_mem_copy(cc_db->elected_cc, cc_db->votes[j].cc,
+ REG_ALPHA2_LEN + 1);
+
+ scm_debug("Selected Country is %c%c With count %d",
+ cc_db->votes[j].cc[0],
+ cc_db->votes[j].cc[1],
+ cc_db->votes[j].votes);
+
+ return true;
+}
+
+/**
+ * scm_11d_set_country_code - private api to set cc per 11d learning
+ * @pdev: pdev object
+ * @elected_cc: elected country code
+ * @current_cc: current country code
+ *
+ * Return: true or false
+ */
+static bool
+scm_11d_set_country_code(struct wlan_objmgr_pdev *pdev,
+ uint8_t *elected_cc, uint8_t *current_cc)
+{
+ scm_debug("elected country %c%c, current country %c%c",
+ elected_cc[0], elected_cc[1], current_cc[0], current_cc[1]);
+
+ if (!qdf_mem_cmp(elected_cc, current_cc, REG_ALPHA2_LEN + 1))
+ return true;
+
+ wlan_reg_set_11d_country(pdev, elected_cc);
+ return true;
+}
+
+/**
+ * scm_11d_reset_cc_db - reset the country code db
+ * @cc_db: the pointer of country code db
+ *
+ * Return: void
+ */
+static void scm_11d_reset_cc_db(struct scan_country_code_db *cc_db)
+{
+ qdf_mem_zero(cc_db->votes, sizeof(cc_db->votes));
+ qdf_mem_zero(cc_db->elected_cc, sizeof(cc_db->elected_cc));
+ cc_db->num_country_codes = 0;
+}
+
+QDF_STATUS scm_11d_cc_db_init(struct wlan_objmgr_psoc *psoc)
+{
+ struct scan_country_code_db *cc_db;
+ struct wlan_scan_obj *scan_obj;
+
+ if (!psoc) {
+ scm_err("psoc is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ scan_obj = wlan_psoc_get_scan_obj(psoc);
+ if (!scan_obj) {
+ scm_err("scan_obj is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ cc_db = (struct scan_country_code_db *)qdf_mem_malloc(
+ sizeof(struct scan_country_code_db) * WLAN_UMAC_MAX_PDEVS);
+ if (!cc_db) {
+ scm_err("alloc country code db error");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ qdf_mem_zero(cc_db,
+ sizeof(struct scan_country_code_db) *
+ WLAN_UMAC_MAX_PDEVS);
+
+ scan_obj->cc_db = cc_db;
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS scm_11d_cc_db_deinit(struct wlan_objmgr_psoc *psoc)
+{
+ struct wlan_scan_obj *scan_obj;
+
+ if (!psoc) {
+ scm_err("psoc is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ scan_obj = wlan_psoc_get_scan_obj(psoc);
+ if (!scan_obj) {
+ scm_err("scan_obj is NULL");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ qdf_mem_free(scan_obj->cc_db);
+ return QDF_STATUS_SUCCESS;
+}
+
+void scm_11d_handle_country_info(struct wlan_objmgr_psoc *psoc,
+ struct wlan_objmgr_pdev *pdev,
+ struct scan_cache_entry *scan_entry)
+{
+ uint8_t i;
+ bool match = false;
+ uint8_t num_country_codes;
+ struct scan_country_code_db *cc_db;
+ struct wlan_country_ie *cc_ie;
+
+ cc_ie = util_scan_entry_country(scan_entry);
+ if (!cc_ie)
+ return;
+
+ cc_db = wlan_pdev_get_cc_db(psoc, pdev);
+ if (!cc_db)
+ return;
+
+ /* just to be sure, convert to UPPER case here */
+ for (i = 0; i < 3; i++)
+ cc_ie->cc[i] = qdf_toupper(cc_ie->cc[i]);
+
+ num_country_codes = cc_db->num_country_codes;
+ for (i = 0; i < num_country_codes; i++) {
+ match = !qdf_mem_cmp(cc_db->votes[i].cc, cc_ie->cc,
+ REG_ALPHA2_LEN);
+ if (match)
+ break;
+ }
+
+ if (match) {
+ cc_db->votes[i].votes++;
+ return;
+ }
+
+ if (num_country_codes >= SCAN_MAX_NUM_COUNTRY_CODE) {
+ scm_debug("country code db already full: %d",
+ num_country_codes);
+ return;
+ }
+
+ /* add country code to end of the list */
+ qdf_mem_copy(cc_db->votes[num_country_codes].cc, cc_ie->cc,
+ REG_ALPHA2_LEN + 1);
+ cc_db->votes[num_country_codes].votes = 1;
+ cc_db->num_country_codes++;
+}
+
+void scm_11d_decide_country_code(struct wlan_objmgr_vdev *vdev)
+{
+ uint8_t current_cc[REG_ALPHA2_LEN + 1];
+ bool found;
+ struct scan_country_code_db *cc_db;
+ struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev);
+ struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+
+ if (!wlan_reg_11d_enabled_on_host(psoc)) {
+ scm_err("11d is not enabled");
+ return;
+ }
+
+ if (SOURCE_UNKNOWN == ucfg_reg_get_cc_and_src(psoc, current_cc)) {
+ scm_err("fail to get current country code");
+ return;
+ }
+
+ cc_db = wlan_pdev_get_cc_db(psoc, pdev);
+ if (!cc_db) {
+ scm_err("scan_db is NULL");
+ return;
+ }
+
+ if (wlan_reg_is_us(current_cc) || wlan_reg_is_world(current_cc))
+ found = scm_11d_elected_country_algo_fcc(cc_db);
+ else
+ found = scm_11d_elected_country_info(cc_db);
+
+ if (found)
+ scm_11d_set_country_code(pdev, cc_db->elected_cc,
+ current_cc);
+ scm_11d_reset_cc_db(cc_db);
+}
diff --git a/umac/scan/core/src/wlan_scan_11d.h b/umac/scan/core/src/wlan_scan_11d.h
new file mode 100644
index 000000000..9ec31b7fc
--- /dev/null
+++ b/umac/scan/core/src/wlan_scan_11d.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * DOC: contains scan 11d entry api
+ */
+
+#ifndef _WLAN_SCAN_11D_H_
+#define _WLAN_SCAN_11D_H_
+
+#define SCAN_MAX_NUM_COUNTRY_CODE 100
+#define MIN_11D_AP_COUNT 3
+
+/**
+ * struct scan_country_code_votes - votes to country code mapping structure
+ * @votes: votes
+ * @cc: country code
+ */
+struct scan_country_code_votes {
+ uint16_t votes;
+ uint8_t cc[REG_ALPHA2_LEN + 1];
+};
+
+/**
+ * struct scan_country_code_db - country code data base definition
+ * @elected_cc: elected country code
+ * @num_country_codes: number of country codes encountered
+ * @votes: votes to country code mapping array
+ */
+struct scan_country_code_db {
+ uint8_t elected_cc[REG_ALPHA2_LEN + 1];
+ uint8_t num_country_codes;
+ struct scan_country_code_votes votes[SCAN_MAX_NUM_COUNTRY_CODE];
+};
+
+/**
+ * scm_11d_cc_db_init() - API to init 11d country code db
+ * @psoc: psoc object
+ *
+ * Initialize the country code database.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS scm_11d_cc_db_init(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * scm_11d_cc_db_deinit() - API to deinit 11d country code db
+ * @psoc: psoc object
+ *
+ * free the country code database.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS scm_11d_cc_db_deinit(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * scm_11d_handle_country_info() - API to handle 11d country info
+ * @psoc: psoc object
+ * @pdev: pdev object
+ * @scan_entry: the pointer to scan entry
+ *
+ * Update the country code database per the country code from country IE.
+ *
+ * Return: void
+ */
+void scm_11d_handle_country_info(struct wlan_objmgr_psoc *psoc,
+ struct wlan_objmgr_pdev *pdev,
+ struct scan_cache_entry *scan_entry);
+
+/**
+ * scm_11d_decide_country_code() - API to decide the country code per 11d
+ * @vdev: vdev object
+ *
+ * Decide which country will be elected from the country database. If one
+ * cadidate country is found, then it set the country code.
+ *
+ * Return: void
+ */
+void scm_11d_decide_country_code(struct wlan_objmgr_vdev *vdev);
+#endif
diff --git a/umac/scan/core/src/wlan_scan_cache_db.c b/umac/scan/core/src/wlan_scan_cache_db.c
index fced2b4b2..e3a23c8a6 100644
--- a/umac/scan/core/src/wlan_scan_cache_db.c
+++ b/umac/scan/core/src/wlan_scan_cache_db.c
@@ -37,6 +37,8 @@
#include <wlan_scan_utils_api.h>
#include "wlan_scan_main.h"
#include "wlan_scan_cache_db_i.h"
+#include "wlan_reg_services_api.h"
+#include "wlan_reg_ucfg_api.h"
/**
* scm_del_scan_node() - API to remove scan node from the list
@@ -692,6 +694,9 @@ QDF_STATUS scm_handle_bcn_probe(struct scheduler_msg *msg)
scan_entry = scan_node->entry;
+ if (wlan_reg_11d_enabled_on_host(psoc))
+ scm_11d_handle_country_info(psoc, pdev, scan_entry);
+
status = scm_add_update_entry(scan_db, scan_entry);
if (QDF_IS_STATUS_ERROR(status)) {
util_scan_free_cache_entry(scan_entry);
diff --git a/umac/scan/core/src/wlan_scan_filter.c b/umac/scan/core/src/wlan_scan_filter.c
index 4e057e67e..6bcd44ac5 100644
--- a/umac/scan/core/src/wlan_scan_filter.c
+++ b/umac/scan/core/src/wlan_scan_filter.c
@@ -893,6 +893,7 @@ bool scm_filter_match(struct wlan_objmgr_psoc *psoc,
bool match = false;
struct roam_filter_params *roam_params;
struct scan_default_params *def_param;
+ struct wlan_country_ie *cc_ie;
def_param = wlan_scan_psoc_get_def_params(psoc);
if (!def_param)
@@ -972,8 +973,8 @@ bool scm_filter_match(struct wlan_objmgr_psoc *psoc,
if (!scm_is_fils_config_match(filter, db_entry))
return false;
- if (!util_country_code_match(filter->country,
- db_entry->ie_list.country))
+ cc_ie = util_scan_entry_country(db_entry);
+ if (!util_country_code_match(filter->country, cc_ie))
return false;
if (!util_mdie_match(filter->mobility_domain,
diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h
index 82f66b825..1342fe66f 100644
--- a/umac/scan/core/src/wlan_scan_main.h
+++ b/umac/scan/core/src/wlan_scan_main.h
@@ -29,6 +29,7 @@
#include <wlan_objmgr_vdev_obj.h>
#include <wlan_scan_public_structs.h>
#include "wlan_scan_cache_db.h"
+#include "wlan_scan_11d.h"
#define scm_log(level, args...) \
QDF_TRACE(QDF_MODULE_ID_SCAN, level, ## args)
@@ -396,6 +397,7 @@ struct scan_cb {
* struct wlan_scan_obj - scan object definition
* @enable_scan: if scan is enabled
* @scan_db: scan cache data base
+ * @cc_db: pointer of country code data base
* @lock: spin lock
* @scan_def: default scan parameters
* @cb: nif/sif function callbacks
@@ -414,6 +416,7 @@ struct wlan_scan_obj {
qdf_spinlock_t lock;
qdf_atomic_t scan_ids;
struct scan_dbs scan_db[WLAN_UMAC_MAX_PDEVS];
+ struct scan_country_code_db *cc_db;
struct scan_default_params scan_def;
struct scan_cb cb;
struct scan_requester_info requesters[WLAN_MAX_REQUESTORS];
diff --git a/umac/scan/core/src/wlan_scan_manager.c b/umac/scan/core/src/wlan_scan_manager.c
index 8d27d112d..b8fbc6e07 100644
--- a/umac/scan/core/src/wlan_scan_manager.c
+++ b/umac/scan/core/src/wlan_scan_manager.c
@@ -727,6 +727,8 @@ scm_scan_event_handler(struct scheduler_msg *msg)
switch (event->type) {
case SCAN_EVENT_TYPE_COMPLETED:
+ scm_11d_decide_country_code(vdev);
+ /* fall through to release the command */
case SCAN_EVENT_TYPE_START_FAILED:
case SCAN_EVENT_TYPE_DEQUEUED:
scm_release_serialization_command(vdev, event->scan_id);
diff --git a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h
index 020abcd13..dbcc302f7 100644
--- a/umac/scan/dispatcher/inc/wlan_scan_utils_api.h
+++ b/umac/scan/dispatcher/inc/wlan_scan_utils_api.h
@@ -339,11 +339,8 @@ static inline bool util_is_bss_type_match(enum wlan_bss_type bss_type,
* Return: true if country match
*/
static inline bool util_country_code_match(uint8_t *country,
- uint8_t *country_ie)
+ struct wlan_country_ie *cc)
{
- struct wlan_country_ie *cc =
- (struct wlan_country_ie *)country;
-
if (!country || !country[0])
return true;
@@ -351,7 +348,7 @@ static inline bool util_country_code_match(uint8_t *country,
return false;
if (cc->cc[0] == country[0] &&
- cc->cc[1] == country[1])
+ cc->cc[1] == country[1])
return true;
return false;
@@ -1034,10 +1031,10 @@ util_scan_entry_vendor(struct scan_cache_entry *scan_entry)
*
* Return: countryie or NULL if ie is not present
*/
-static inline uint8_t*
+static inline struct wlan_country_ie*
util_scan_entry_country(struct scan_cache_entry *scan_entry)
{
- return scan_entry->ie_list.country;
+ return (struct wlan_country_ie *)scan_entry->ie_list.country;
}
/**
@@ -1060,8 +1057,7 @@ util_scan_entry_copy_country(struct scan_cache_entry *scan_entry,
if (!cntry)
return QDF_STATUS_E_INVAL;
- country_ie = (struct wlan_country_ie *)
- util_scan_entry_country(scan_entry);
+ country_ie = util_scan_entry_country(scan_entry);
if (!country_ie)
return QDF_STATUS_E_NOMEM;
diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
index 0a2f730f7..b882b410f 100644
--- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
+++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c
@@ -1722,6 +1722,8 @@ ucfg_scan_psoc_enable(struct wlan_objmgr_psoc *psoc)
status = tgt_scan_register_ev_handler(psoc);
QDF_ASSERT(status == QDF_STATUS_SUCCESS);
scm_db_init(psoc);
+ if (wlan_reg_11d_original_enabled_on_host(psoc))
+ scm_11d_cc_db_init(psoc);
ucfg_scan_register_unregister_bcn_cb(psoc, true);
status = wlan_serialization_register_apply_rules_cb(psoc,
WLAN_SER_CMD_SCAN,
@@ -1744,6 +1746,8 @@ ucfg_scan_psoc_disable(struct wlan_objmgr_psoc *psoc)
status = tgt_scan_unregister_ev_handler(psoc);
QDF_ASSERT(status == QDF_STATUS_SUCCESS);
ucfg_scan_register_unregister_bcn_cb(psoc, false);
+ if (wlan_reg_11d_original_enabled_on_host(psoc))
+ scm_11d_cc_db_deinit(psoc);
scm_db_deinit(psoc);
return status;