qcacmn: Add changes to get/flush scan results

Add changes to get/flush scan results. Also add support to
filter results depending on the filter passed.

Change-Id: Iefb297ef19058299fa26b9bb61202e902e5fd465
CRs-Fixed: 1095299
Dieser Commit ist enthalten in:
Abhishek Singh
2017-02-21 15:19:55 +05:30
committet von qcabuildsw
Ursprung 8f87b9515a
Commit 37bf2e0dca
4 geänderte Dateien mit 1590 neuen und 0 gelöschten Zeilen

Datei anzeigen

@@ -569,6 +569,443 @@ free_nbuf:
return status;
}
/**
* scm_list_insert_sorted() - add the entries in scan_list in sorted way
* @filter: scan filter
* @scan_node: node entry to be inserted
* @scan_list: Temp scan list
*
* Add the entries in scan_list in sorted way considering
* cap_val and prefer val. The node is copy of original scan entry and
* thus no lock is required.
*
* Return: void
*/
static void scm_list_insert_sorted(struct scan_filter *filter,
struct scan_cache_node *scan_node,
qdf_list_t *scan_list)
{
struct scan_cache_node *cur_node;
qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
scan_node->entry->cap_val =
scm_get_bss_cap_value(filter, scan_node->entry);
scan_node->entry->prefer_value =
scm_get_bss_prefer_value(filter, scan_node->entry);
if (filter->num_of_pcl_channels)
scm_calc_pref_val_by_pcl(filter, scan_node->entry);
if (qdf_list_empty(scan_list)) {
qdf_list_insert_front(scan_list, &scan_node->node);
return;
}
qdf_list_peek_front(scan_list, &cur_lst);
while (cur_lst) {
cur_node = qdf_container_of(cur_lst,
struct scan_cache_node, node);
if (scm_is_better_bss(filter,
scan_node->entry, cur_node->entry)) {
qdf_list_insert_before(scan_list,
&scan_node->node,
&cur_node->node);
break;
}
qdf_list_peek_next(scan_list,
cur_lst, &next_lst);
next_lst = next_lst;
next_lst = NULL;
}
if (!cur_lst)
qdf_list_insert_back(scan_list,
&scan_node->node);
}
/**
* scm_scan_apply_filter_get_entry() - apply filter and get the
* scan entry
* @db_entry: scan entry
* @filter: filter to be applied
* @scan_list: scan list to which entry is added
*
* Return: QDF_STATUS
*/
static QDF_STATUS
scm_scan_apply_filter_get_entry(struct scan_cache_entry *db_entry,
struct scan_filter *filter,
qdf_list_t *scan_list)
{
struct scan_cache_node *scan_node = NULL;
struct security_info security = {0};
bool match;
if (!filter)
match = true;
else
match = scm_filter_match(db_entry, filter, &security);
if (!match)
return QDF_STATUS_SUCCESS;
scan_node = qdf_mem_malloc(sizeof(*scan_node));
if (!scan_node)
return QDF_STATUS_E_NOMEM;
scan_node->entry =
util_scan_copy_cache_entry(db_entry);
if (!scan_node->entry) {
qdf_mem_free(scan_node);
return QDF_STATUS_E_NOMEM;
}
qdf_mem_copy(&scan_node->entry->neg_sec_info,
&security, sizeof(scan_node->entry->neg_sec_info));
if (!filter)
qdf_list_insert_front(scan_list,
&scan_node->node);
else
scm_list_insert_sorted(filter, scan_node, scan_list);
return QDF_STATUS_SUCCESS;
}
/**
* scm_get_results() - Iterate and get scan results
* @scan_db: scan db
* @filter: filter to be applied
* @scan_list: scan list to which entry is added
*
* Return: void
*/
static void scm_get_results(struct scan_dbs *scan_db,
struct scan_filter *filter,
qdf_list_t *scan_list)
{
int i;
struct scan_cache_node *cur_node;
struct scan_cache_node *next_node = NULL;
for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
cur_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], NULL);
while (cur_node) {
scm_scan_apply_filter_get_entry(
cur_node->entry, filter, scan_list);
next_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], cur_node);
cur_node = next_node;
}
}
}
QDF_STATUS scm_purge_scan_results(qdf_list_t *scan_list)
{
QDF_STATUS status;
struct scan_cache_node *cur_node;
qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
if (!scan_list) {
scm_err("scan_result is NULL");
return QDF_STATUS_E_INVAL;
}
status = qdf_list_peek_front(scan_list, &cur_lst);
while (cur_lst) {
qdf_list_peek_next(
scan_list, cur_lst, &next_lst);
cur_node = qdf_container_of(cur_lst,
struct scan_cache_node, node);
status = qdf_list_remove_node(scan_list,
cur_lst);
if (QDF_IS_STATUS_SUCCESS(status)) {
util_scan_free_cache_entry(cur_node->entry);
qdf_mem_free(cur_node);
}
cur_lst = next_lst;
next_lst = NULL;
}
qdf_list_destroy(scan_list);
qdf_mem_free(scan_list);
return status;
}
qdf_list_t *scm_get_scan_result(struct wlan_objmgr_pdev *pdev,
struct scan_filter *filter)
{
struct wlan_objmgr_psoc *psoc;
struct scan_dbs *scan_db;
qdf_list_t *tmp_list;
if (!pdev) {
scm_err("pdev is NULL");
return NULL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
scm_err("psoc is NULL");
return NULL;
}
scan_db = wlan_pdev_get_scan_db(psoc, pdev);
if (!scan_db) {
scm_err("scan_db is NULL");
return NULL;
}
tmp_list = qdf_mem_malloc(sizeof(*tmp_list));
if (!tmp_list) {
scm_err("failed tp allocate scan_result");
return NULL;
}
qdf_list_create(tmp_list,
MAX_SCAN_CACHE_SIZE);
scm_age_out_entries(scan_db);
scm_get_results(scan_db, filter, tmp_list);
return tmp_list;
}
/**
* scm_iterate_db_and_call_func() - iterate and call the func
* @scan_db: scan db
* @func: func to be called
* @arg: func arg
*
* Return: QDF_STATUS
*/
static QDF_STATUS
scm_iterate_db_and_call_func(struct scan_dbs *scan_db,
scan_iterator_func func, void *arg)
{
int i;
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct scan_cache_node *cur_node;
struct scan_cache_node *next_node = NULL;
if (!func)
return QDF_STATUS_E_INVAL;
for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
cur_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], NULL);
while (cur_node) {
status = func(arg, cur_node->entry);
if (QDF_IS_STATUS_ERROR(status)) {
scm_scan_entry_put_ref(scan_db,
cur_node, true);
return status;
}
next_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], cur_node);
cur_node = next_node;
}
}
return status;
}
QDF_STATUS
scm_iterate_scan_db(struct wlan_objmgr_pdev *pdev,
scan_iterator_func func, void *arg)
{
struct wlan_objmgr_psoc *psoc;
struct scan_dbs *scan_db;
QDF_STATUS status;
if (!func) {
scm_err("func is NULL");
return QDF_STATUS_E_INVAL;
}
if (!pdev) {
scm_err("pdev is NULL");
return QDF_STATUS_E_INVAL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
scm_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
scan_db = wlan_pdev_get_scan_db(psoc, pdev);
if (!scan_db) {
scm_err("scan_db is NULL");
return QDF_STATUS_E_INVAL;
}
scm_age_out_entries(scan_db);
status = scm_iterate_db_and_call_func(scan_db, func, arg);
return status;
}
/**
* scm_scan_apply_filter_flush_entry() -flush scan entries depending
* on filter
* @scan_db: scan db
* @db_node: node on which filters are applied
* @filter: filter to be applied
*
* Return: QDF_STATUS
*/
static QDF_STATUS
scm_scan_apply_filter_flush_entry(struct scan_dbs *scan_db,
struct scan_cache_node *db_node,
struct scan_filter *filter)
{
struct security_info security = {0};
bool match;
if (!filter)
match = true;
else
match = scm_filter_match(db_node->entry, filter, &security);
if (!match)
return QDF_STATUS_SUCCESS;
scm_scan_entry_put_ref(scan_db, db_node, true);
return QDF_STATUS_SUCCESS;
}
/**
* scm_flush_scan_entries() - API to flush scan entries depending on filters
* @scan_db: scan db
* @filter: filter
*
* Return: void
*/
static void scm_flush_scan_entries(struct scan_dbs *scan_db,
struct scan_filter *filter)
{
int i;
struct scan_cache_node *cur_node;
struct scan_cache_node *next_node = NULL;
for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
cur_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], NULL);
while (cur_node) {
scm_scan_apply_filter_flush_entry(scan_db,
cur_node, filter);
next_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], cur_node);
cur_node = next_node;
}
}
}
QDF_STATUS scm_flush_results(struct wlan_objmgr_pdev *pdev,
struct scan_filter *filter)
{
struct wlan_objmgr_psoc *psoc;
struct scan_dbs *scan_db;
QDF_STATUS status = QDF_STATUS_SUCCESS;
if (!pdev) {
scm_err("pdev is NULL");
return QDF_STATUS_E_INVAL;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
scm_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
scan_db = wlan_pdev_get_scan_db(psoc, pdev);
if (!scan_db) {
scm_err("scan_db is NULL");
return QDF_STATUS_E_INVAL;
}
scm_flush_scan_entries(scan_db, filter);
return status;
}
/**
* scm_filter_channels() - Remove entries not belonging to channel list
* @scan_db: scan db
* @db_node: node on which filters are applied
* @chan_list: valid channel list
* @num_chan: number of channels
*
* Return: QDF_STATUS
*/
static void scm_filter_channels(struct scan_dbs *scan_db,
struct scan_cache_node *db_node,
uint8_t *chan_list, uint32_t num_chan)
{
int i;
bool match = false;
for (i = 0; i < num_chan; i++) {
if (chan_list[i] ==
util_scan_entry_channel_num(db_node->entry)) {
match = true;
break;
}
}
if (!match)
scm_scan_entry_put_ref(scan_db, db_node, true);
}
void scm_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
uint8_t *chan_list, uint32_t num_chan)
{
int i;
struct wlan_objmgr_psoc *psoc;
struct scan_dbs *scan_db;
struct scan_cache_node *cur_node;
struct scan_cache_node *next_node = NULL;
scm_info("num_chan = %d", num_chan);
if (!pdev) {
scm_err("pdev is NULL");
return;
}
psoc = wlan_pdev_get_psoc(pdev);
if (!psoc) {
scm_err("psoc is NULL");
return;
}
scan_db = wlan_pdev_get_scan_db(psoc, pdev);
if (!scan_db) {
scm_err("scan_db is NULL");
return;
}
for (i = 0 ; i < SCAN_HASH_SIZE; i++) {
cur_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], NULL);
while (cur_node) {
scm_filter_channels(scan_db,
cur_node, chan_list, num_chan);
next_node = scm_get_next_node(scan_db,
&scan_db->scan_hash_tbl[i], cur_node);
cur_node = next_node;
}
}
}
QDF_STATUS scm_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
update_beacon_cb cb, enum scan_cb_type type)
{
@@ -638,6 +1075,7 @@ QDF_STATUS scm_db_deinit(struct wlan_objmgr_psoc *psoc)
continue;
}
scm_flush_scan_entries(scan_db, NULL);
for (j = 0; j < SCAN_HASH_SIZE; j++)
qdf_list_destroy(&scan_db->scan_hash_tbl[j]);
qdf_spinlock_destroy(&scan_db->scan_db_lock);

Datei anzeigen

@@ -23,6 +23,126 @@
#ifndef _WLAN_SCAN_CACHE_DB_I_H_
#define _WLAN_SCAN_CACHE_DB_I_H_
/**
* scm_filter_match() - private API to check if entry is match to filter
* @db_entry: db entry
* @filter: filter
* @security: negotiated security if match is found
*
* Return: true if entry match filter
*/
bool scm_filter_match(struct scan_cache_entry *db_entry,
struct scan_filter *filter,
struct security_info *security);
/**
* scm_get_bss_prefer_value() - Get the preference value for BSS
* @filter: scan filter
* @entry: entry
*
* Each BSS should be assigned a preference value ranging from
* 14-0, which will be used as an RSSI bucket score while sorting the
* scan results.
*
* Return: Preference value for the BSSID
*/
uint32_t scm_get_bss_prefer_value(struct scan_filter *filter,
struct scan_cache_entry *entry);
/**
* scm_is_better_bss() - Is bss1 better than bss2
* @filter: scan filter
* @bss1: Pointer to the first BSS.
* @bss2: Pointer to the second BSS.
*
* This routine helps in determining the preference value
* of a particular BSS in the scan result which is further
* used in the sorting logic of the final candidate AP's.
*
* Return: true, if bss1 is better than bss2
* false, if bss2 is better than bss1.
*/
bool scm_is_better_bss(struct scan_filter *filter,
struct scan_cache_entry *bss1,
struct scan_cache_entry *bss2);
/**
* scm_get_bss_cap_value() - get bss capability value
* @filter: filter
* @entry: scan entry entry
*
* Return: CapValue base on the capabilities of a BSS
*/
uint32_t scm_get_bss_cap_value(struct scan_filter *filter,
struct scan_cache_entry *entry);
/**
* is_channel_found_in_pcl() - to check if channel is present in pcl
* @channel_id: channel of bss
* @filter: pointer to filter created through profile
*
* to check if provided channel is present in pcl
*
* Return: true or false
*/
static inline bool is_channel_found_in_pcl(int channel_id,
struct scan_filter *filter)
{
int i;
bool status = false;
if (!filter)
return status;
for (i = 0; i < filter->num_of_pcl_channels; i++) {
if (filter->pcl_channel_list[i] == channel_id) {
status = true;
break;
}
}
return status;
}
/**
* scm_derive_prefer_value_from_rssi() - to derive prefer value
* @filter: filter
* @rssi: RSSI of the BSS
*
* This routine will derive preferred value from given rssi
*
* Return: value between 0 to 14
*/
static inline int scm_derive_prefer_value_from_rssi(struct scan_filter *filter,
int rssi)
{
int i = SCM_NUM_RSSI_CAT - 1, pref_val = 0;
while (i >= 0) {
if (rssi >= filter->rssi_cat[i]) {
pref_val = filter->bss_prefer_val[i];
break;
}
i--;
};
return pref_val;
}
/**
* scm_calc_pref_val_by_pcl() - to calculate preferred value
* @filter: filter to find match from scan result
* @bss_descr: pointer to bss descriptor
*
* this routine calculates the new preferred value to be given to
* provided bss if its channel falls under preferred channel list.
* Thump rule is higer the RSSI better the boost.
*
* Return: success or failure
*/
QDF_STATUS scm_calc_pref_val_by_pcl(struct scan_filter *filter,
struct scan_cache_entry *entry);
/**
* wlan_pdevid_get_scan_db() - private API to get scan db from pdev id
* @psoc: psoc object

Datei-Diff unterdrückt, da er zu groß ist Diff laden

Datei anzeigen

@@ -36,6 +36,35 @@ QDF_STATUS ucfg_scan_register_bcn_cb(struct wlan_objmgr_psoc *psoc,
return scm_scan_register_bcn_cb(psoc, cb, type);
}
qdf_list_t *ucfg_scan_get_result(struct wlan_objmgr_pdev *pdev,
struct scan_filter *filter)
{
return scm_get_scan_result(pdev, filter);
}
QDF_STATUS ucfg_scan_db_iterate(struct wlan_objmgr_pdev *pdev,
scan_iterator_func func, void *arg)
{
return scm_iterate_scan_db(pdev, func, arg);
}
QDF_STATUS ucfg_scan_purge_results(qdf_list_t *scan_list)
{
return scm_purge_scan_results(scan_list);
}
QDF_STATUS ucfg_scan_flush_results(struct wlan_objmgr_pdev *pdev,
struct scan_filter *filter)
{
return scm_flush_results(pdev, filter);
}
void ucfg_scan_filter_valid_channel(struct wlan_objmgr_pdev *pdev,
uint8_t *chan_list, uint32_t num_chan)
{
scm_filter_valid_channel(pdev, chan_list, num_chan);
}
QDF_STATUS ucfg_scan_init(void)
{
QDF_STATUS status;