diff options
author | Paul Zhang <paulz@codeaurora.org> | 2018-02-02 17:43:37 +0800 |
---|---|---|
committer | snandini <snandini@codeaurora.org> | 2018-02-08 21:37:37 -0800 |
commit | ca6152167b9744d62723f49e6436a30c9366cb1d (patch) | |
tree | 5c36bcbfbba4fe58743c6d2902a9281ecbe29cc9 /umac | |
parent | e6d32a9f381fba48ec49fd5c703c76a4c3c7f453 (diff) | |
download | qca-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.c | 94 | ||||
-rw-r--r-- | umac/regulatory/core/src/reg_services.h | 33 | ||||
-rw-r--r-- | umac/regulatory/dispatcher/inc/wlan_reg_services_api.h | 36 | ||||
-rw-r--r-- | umac/regulatory/dispatcher/src/wlan_reg_services_api.c | 21 | ||||
-rw-r--r-- | umac/scan/core/src/wlan_scan_11d.c | 354 | ||||
-rw-r--r-- | umac/scan/core/src/wlan_scan_11d.h | 95 | ||||
-rw-r--r-- | umac/scan/core/src/wlan_scan_cache_db.c | 5 | ||||
-rw-r--r-- | umac/scan/core/src/wlan_scan_filter.c | 5 | ||||
-rw-r--r-- | umac/scan/core/src/wlan_scan_main.h | 3 | ||||
-rw-r--r-- | umac/scan/core/src/wlan_scan_manager.c | 2 | ||||
-rw-r--r-- | umac/scan/dispatcher/inc/wlan_scan_utils_api.h | 14 | ||||
-rw-r--r-- | umac/scan/dispatcher/src/wlan_scan_ucfg_api.c | 4 |
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; |