From d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:45:28 +0000 Subject: [PATCH] add boot partition size --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c | 2835 +++++++++++++++++++++++++++++++++-------------------------- 1 files changed, 1,584 insertions(+), 1,251 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c index 418a01f..e01c7ff 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/dhd_pno.c @@ -1,16 +1,17 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Broadcom Dongle Host Driver (DHD) * Prefered Network Offload and Wi-Fi Location Service(WLS) code. * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -18,7 +19,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -26,12 +27,12 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$ + * $Id: dhd_pno.c 812762 2019-04-02 09:36:26Z $ */ #if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT) #error "GSCAN needs PNO to be enabled!" -#endif +#endif // endif #ifdef PNO_SUPPORT #include <typedefs.h> @@ -41,21 +42,27 @@ #include <bcmutils.h> #include <bcmendian.h> +#ifdef OEM_ANDROID #include <linuxver.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/sort.h> +#endif // endif #include <dngl_stats.h> #include <wlioctl.h> -#include <proto/bcmevent.h> +#include <bcmevent.h> #include <dhd.h> +#include <dhd_linux.h> #include <dhd_pno.h> #include <dhd_dbg.h> #ifdef GSCAN_SUPPORT #include <linux/gcd.h> #endif /* GSCAN_SUPPORT */ +#ifdef WL_CFG80211 +#include <wl_cfg80211.h> +#endif /* WL_CFG80211 */ #ifdef __BIG_ENDIAN #include <bcmendian.h> @@ -74,20 +81,21 @@ #define dtohchanspec(i) (i) #endif /* IL_BIGENDINA */ -#define NULL_CHECK(p, s, err) \ - do { \ - if (!(p)) { \ - printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \ - err = BCME_ERROR; \ - return err; \ - } \ - } while (0) +#ifdef OEM_ANDROID #define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state) -#define PNO_BESTNET_LEN 2048 + +#define PNO_BESTNET_LEN WLC_IOCTL_MEDLEN + #define PNO_ON 1 #define PNO_OFF 0 +#define CHANNEL_2G_MIN 1 #define CHANNEL_2G_MAX 14 +#define CHANNEL_5G_MIN 34 #define CHANNEL_5G_MAX 165 +#define IS_2G_CHANNEL(ch) ((ch >= CHANNEL_2G_MIN) && \ + (ch <= CHANNEL_2G_MAX)) +#define IS_5G_CHANNEL(ch) ((ch >= CHANNEL_5G_MIN) && \ + (ch <= CHANNEL_5G_MAX)) #define MAX_NODE_CNT 5 #define WLS_SUPPORTED(pno_state) (pno_state->wls_supported == TRUE) #define TIME_DIFF(timestamp1, timestamp2) (abs((uint32)(timestamp1/1000) \ @@ -99,30 +107,46 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 -#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) -#define EVENT_MAX_NETCNT \ - ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_t)) \ - / sizeof(wl_pfn_net_info_t) + 1) -#define WL_SCAN_IE_LEN_MAX 2048 -static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state); +#define EVENT_DATABUF_MAXLEN (512 - sizeof(bcm_event_t)) +#define EVENT_MAX_NETCNT_V1 \ + ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v1_t)) \ + / sizeof(wl_pfn_net_info_v1_t) + 1) +#define EVENT_MAX_NETCNT_V2 \ + ((EVENT_DATABUF_MAXLEN - sizeof(wl_pfn_scanresults_v2_t)) \ + / sizeof(wl_pfn_net_info_v2_t) + 1) + #ifdef GSCAN_SUPPORT +static int _dhd_pno_flush_ssid(dhd_pub_t *dhd); static wl_pfn_gscan_ch_bucket_cfg_t * dhd_pno_gscan_create_channel_list(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state, - uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); + uint16 *chan_list, uint32 *num_buckets, uint32 *num_buckets_to_fw); #endif /* GSCAN_SUPPORT */ +static int dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16 scan_fr, int pno_repeat, + int pno_freq_expo_max, uint16 *channel_list, int nchan); + static inline bool -is_dfs(uint16 channel) +is_dfs(dhd_pub_t *dhd, uint16 channel) { - if (channel >= 52 && channel <= 64) /* class 2 */ - return TRUE; - else if (channel >= 100 && channel <= 140) /* class 4 */ - return TRUE; - else + u32 ch; + s32 err; + u8 buf[32]; + + ch = wl_ch_host_to_driver(channel); + err = dhd_iovar(dhd, 0, "per_chan_info", (char *)&ch, + sizeof(u32), buf, sizeof(buf), FALSE); + if (unlikely(err)) { + DHD_ERROR(("get per chan info failed:%d\n", err)); return FALSE; + } + /* Check the channel flags returned by fw */ + if (*((u32 *)buf) & WL_CHAN_PASSIVE) { + return TRUE; + } + return FALSE; } + int dhd_pno_clean(dhd_pub_t *dhd) { @@ -180,33 +204,100 @@ #ifdef GSCAN_SUPPORT static uint64 -convert_fw_rel_time_to_systime(uint32 fw_ts_ms) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) +convert_fw_rel_time_to_systime(struct timespec64 *ts, uint32 fw_ts_ms) +#else +convert_fw_rel_time_to_systime(struct timespec *ts, uint32 fw_ts_ms) +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */ { - struct timespec ts; - - get_monotonic_boottime(&ts); - return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000)); + return ((uint64)(TIMESPEC_TO_US(*ts)) - (uint64)(fw_ts_ms * 1000)); } static void dhd_pno_idx_to_ssid(struct dhd_pno_gscan_params *gscan_params, - dhd_epno_results_t *res, uint32 idx) + dhd_epno_results_t *res, uint32 idx) { - dhd_epno_params_t *iter, *next; + dhd_pno_ssid_t *iter, *next; + int i; - if (gscan_params->num_epno_ssid > 0) { + /* If idx doesn't make sense */ + if (idx >= gscan_params->epno_cfg.num_epno_ssid) { + DHD_ERROR(("No match, idx %d num_ssid %d\n", idx, + gscan_params->epno_cfg.num_epno_ssid)); + goto exit; + } + + if (gscan_params->epno_cfg.num_epno_ssid > 0) { + i = 0; + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, - &gscan_params->epno_ssid_list, list) { - if (iter->index == idx) { - memcpy(res->ssid, iter->ssid, iter->ssid_len); - res->ssid_len = iter->ssid_len; + &gscan_params->epno_cfg.epno_ssid_list, list) { + GCC_DIAGNOSTIC_POP(); + if (i++ == idx) { + memcpy(res->ssid, iter->SSID, iter->SSID_len); + res->ssid_len = iter->SSID_len; return; } } } +exit: /* If we are here then there was no match */ res->ssid[0] = '\0'; res->ssid_len = 0; + return; +} + +/* Translate HAL flag bitmask to BRCM FW flag bitmask */ +void +dhd_pno_translate_epno_fw_flags(uint32 *flags) +{ + uint32 in_flags, fw_flags = 0; + in_flags = *flags; + + if (in_flags & DHD_EPNO_A_BAND_TRIG) { + fw_flags |= WL_PFN_SSID_A_BAND_TRIG; + } + + if (in_flags & DHD_EPNO_BG_BAND_TRIG) { + fw_flags |= WL_PFN_SSID_BG_BAND_TRIG; + } + + if (!(in_flags & DHD_EPNO_STRICT_MATCH) && + !(in_flags & DHD_EPNO_HIDDEN_SSID)) { + fw_flags |= WL_PFN_SSID_IMPRECISE_MATCH; + } + + if (in_flags & DHD_EPNO_SAME_NETWORK) { + fw_flags |= WL_PFN_SSID_SAME_NETWORK; + } + + /* Add any hard coded flags needed */ + fw_flags |= WL_PFN_SUPPRESS_AGING_MASK; + *flags = fw_flags; + + return; +} + +/* Translate HAL auth bitmask to BRCM FW bitmask */ +void +dhd_pno_set_epno_auth_flag(uint32 *wpa_auth) +{ + switch (*wpa_auth) { + case DHD_PNO_AUTH_CODE_OPEN: + *wpa_auth = WPA_AUTH_DISABLED; + break; + case DHD_PNO_AUTH_CODE_PSK: + *wpa_auth = (WPA_AUTH_PSK | WPA2_AUTH_PSK); + break; + case DHD_PNO_AUTH_CODE_EAPOL: + *wpa_auth = ~WPA_AUTH_NONE; + break; + default: + DHD_ERROR(("%s: Unknown auth %d", __FUNCTION__, *wpa_auth)); + *wpa_auth = WPA_AUTH_PFN_ANY; + break; + } return; } @@ -244,6 +335,21 @@ goto exit; } exit: + return err; +} + +static int +_dhd_pno_flush_ssid(dhd_pub_t *dhd) +{ + int err; + wl_pfn_t pfn_elem; + memset(&pfn_elem, 0, sizeof(wl_pfn_t)); + pfn_elem.flags = htod32(WL_PFN_FLUSH_ALL_SSIDS); + + err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_elem, sizeof(wl_pfn_t), NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); + } return err; } @@ -298,7 +404,7 @@ } if (enable) { if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && - dhd_is_associated(dhd, NULL, NULL)) { + dhd_is_associated(dhd, 0, NULL)) { DHD_ERROR(("%s Legacy PNO mode cannot be enabled " "in assoc mode , ignore it\n", __FUNCTION__)); err = BCME_BADOPTION; @@ -450,18 +556,17 @@ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - dhd_pno_params_t *_params; + dhd_pno_params_t *params; - _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - pfn_param.scan_freq = htod32(gcd(pno_params->params_gscan.scan_fr, - _params->params_legacy.scan_fr)); + pfn_param.scan_freq = gcd(pno_params->params_gscan.scan_fr, + params->params_legacy.scan_fr); - if ((_params->params_legacy.pno_repeat != 0) || - (_params->params_legacy.pno_freq_expo_max != 0)) { - pfn_param.repeat = (uchar) (_params->params_legacy.pno_repeat); - pfn_param.exp = (uchar) (_params->params_legacy.pno_freq_expo_max); + if ((params->params_legacy.pno_repeat != 0) || + (params->params_legacy.pno_freq_expo_max != 0)) { + pfn_param.repeat = (uchar) (params->params_legacy.pno_repeat); + pfn_param.exp = (uchar) (params->params_legacy.pno_freq_expo_max); } } @@ -494,12 +599,11 @@ } #ifdef GSCAN_SUPPORT - if (mode == DHD_PNO_BATCH_MODE || - ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) { + if (mode == DHD_PNO_BATCH_MODE || + ((mode & DHD_PNO_GSCAN_MODE) && pno_params->params_gscan.mscan)) { #else - if (mode == DHD_PNO_BATCH_MODE) { + if (mode == DHD_PNO_BATCH_MODE) { #endif /* GSCAN_SUPPORT */ - int _tmp = pfn_param.bestn; /* set bestn to calculate the max mscan which firmware supports */ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), NULL, 0, TRUE); @@ -528,69 +632,64 @@ return err; } static int -_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) +_dhd_pno_add_ssid(dhd_pub_t *dhd, struct list_head* ssid_list, int nssid) { int err = BCME_OK; - int i = 0; - wl_pfn_t pfn_element; + int i = 0, mem_needed; + wl_pfn_t *pfn_elem_buf; + struct dhd_pno_ssid *iter, *next; + NULL_CHECK(dhd, "dhd is NULL", err); - if (nssid) { - NULL_CHECK(ssids_list, "ssid list is NULL", err); + if (!nssid) { + NULL_CHECK(ssid_list, "ssid list is NULL", err); + return BCME_ERROR; } - memset(&pfn_element, 0, sizeof(pfn_element)); - { - int j; - for (j = 0; j < nssid; j++) { - DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", - ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden, - ssids_list[j].flags, ssids_list[i].rssi_thresh)); - } + mem_needed = (sizeof(wl_pfn_t) * nssid); + pfn_elem_buf = (wl_pfn_t *) MALLOCZ(dhd->osh, mem_needed); + if (!pfn_elem_buf) { + DHD_ERROR(("%s: Can't malloc %d bytes!\n", __FUNCTION__, mem_needed)); + return BCME_NOMEM; } - /* Check for broadcast ssid */ - for (i = 0; i < nssid; i++) { - if (!ssids_list[i].SSID_len) { - DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i)); - err = BCME_ERROR; - goto exit; - } - } - /* set all pfn ssid */ - for (i = 0; i < nssid; i++) { - pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); - pfn_element.auth = (DOT11_OPEN_SYSTEM); - pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); - pfn_element.wsec = htod32(0); - pfn_element.infra = htod32(1); - if (ssids_list[i].hidden) { - pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); - } else { - pfn_element.flags = 0; - } - pfn_element.flags |= htod32(ssids_list[i].flags); + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + list_for_each_entry_safe(iter, next, ssid_list, list) { + GCC_DIAGNOSTIC_POP(); + pfn_elem_buf[i].infra = htod32(1); + pfn_elem_buf[i].auth = htod32(DOT11_OPEN_SYSTEM); + pfn_elem_buf[i].wpa_auth = htod32(iter->wpa_auth); + pfn_elem_buf[i].flags = htod32(iter->flags); + if (iter->hidden) + pfn_elem_buf[i].flags |= htod32(ENABLE << WL_PFN_HIDDEN_BIT); /* If a single RSSI threshold is defined, use that */ #ifdef PNO_MIN_RSSI_TRIGGER - pfn_element.flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); + pfn_elem_buf[i].flags |= ((PNO_MIN_RSSI_TRIGGER & 0xFF) << WL_PFN_RSSI_SHIFT); #else - pfn_element.flags |= ((ssids_list[i].rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); + pfn_elem_buf[i].flags |= ((iter->rssi_thresh & 0xFF) << WL_PFN_RSSI_SHIFT); #endif /* PNO_MIN_RSSI_TRIGGER */ - memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, - ssids_list[i].SSID_len); - pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; - err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element, sizeof(pfn_element), - NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); - goto exit; + memcpy((char *)pfn_elem_buf[i].ssid.SSID, iter->SSID, + iter->SSID_len); + pfn_elem_buf[i].ssid.SSID_len = iter->SSID_len; + DHD_PNO(("%s size = %d hidden = %d flags = %x rssi_thresh %d\n", + iter->SSID, iter->SSID_len, iter->hidden, + iter->flags, iter->rssi_thresh)); + if (++i >= nssid) { + /* shouldn't happen */ + break; } } -exit: + + err = dhd_iovar(dhd, 0, "pfn_add", (char *)pfn_elem_buf, mem_needed, NULL, 0, TRUE); + if (err < 0) { + DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__)); + } + MFREE(dhd->osh, pfn_elem_buf, mem_needed); return err; } /* qsort compare function */ static int _dhd_pno_cmpfunc(const void *a, const void *b) { - return (*(uint16*)a - *(uint16*)b); + return (*(const uint16*)a - *(const uint16*)b); } static int _dhd_pno_chan_merge(uint16 *d_chan_list, int *nchan, @@ -639,40 +738,43 @@ if (*nchan) { NULL_CHECK(d_chan_list, "d_chan_list is NULL", err); } + memset(&chan_buf, 0, sizeof(chan_buf)); list = (wl_uint32_list_t *) (void *)chan_buf; list->count = htod32(WL_NUMCHANNELS); err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, chan_buf, sizeof(chan_buf), FALSE, 0); if (err < 0) { DHD_ERROR(("failed to get channel list (err: %d)\n", err)); - goto exit; + return err; } for (i = 0, j = 0; i < dtoh32(list->count) && i < *nchan; i++) { - if (band == WLC_BAND_2G) { - if (dtoh32(list->element[i]) > CHANNEL_2G_MAX) + if (IS_2G_CHANNEL(dtoh32(list->element[i]))) { + if (!(band & WLC_BAND_2G)) { + /* Skip, if not 2g */ continue; - } else if (band == WLC_BAND_5G) { - if (dtoh32(list->element[i]) <= CHANNEL_2G_MAX) + } + /* fall through to include the channel */ + } else if (IS_5G_CHANNEL(dtoh32(list->element[i]))) { + bool dfs_channel = is_dfs(dhd, dtoh32(list->element[i])); + if ((skip_dfs && dfs_channel) || + (!(band & WLC_BAND_5G) && !dfs_channel)) { + /* Skip the channel if: + * the DFS bit is NOT set & the channel is a dfs channel + * the band 5G is not set & the channel is a non DFS 5G channel + */ continue; - if (skip_dfs && is_dfs(dtoh32(list->element[i]))) - continue; - - } else if (band == WLC_BAND_AUTO) { - if (skip_dfs || !is_dfs(dtoh32(list->element[i]))) - continue; - - } else { /* All channels */ - if (skip_dfs && is_dfs(dtoh32(list->element[i]))) - continue; - } - if (dtoh32(list->element[i]) <= CHANNEL_5G_MAX) { - d_chan_list[j++] = (uint16) dtoh32(list->element[i]); + } + /* fall through to include the channel */ } else { - err = BCME_BADCHAN; - goto exit; + /* Not in range. Bad channel */ + DHD_ERROR(("Not in range. bad channel\n")); + *nchan = 0; + return BCME_BADCHAN; } + + /* Include the channel */ + d_chan_list[j++] = (uint16) dtoh32(list->element[i]); } *nchan = j; -exit: return err; } static int @@ -689,7 +791,7 @@ #ifdef PNO_DEBUG char *_base_bp; char msg[150]; -#endif +#endif // endif dhd_pno_bestnet_entry_t *iter, *next; dhd_pno_scan_results_t *siter, *snext; dhd_pno_best_header_t *phead, *pprev; @@ -701,15 +803,17 @@ DHD_PNO(("%s enter \n", __FUNCTION__)); /* # of scans */ if (!params_batch->get_batch.batch_started) { - bp += nreadsize = sprintf(bp, "scancount=%d\n", + bp += nreadsize = snprintf(bp, nleftsize, "scancount=%d\n", params_batch->get_batch.expired_tot_scan_cnt); nleftsize -= nreadsize; params_batch->get_batch.batch_started = TRUE; } DHD_PNO(("%s scancount %d\n", __FUNCTION__, params_batch->get_batch.expired_tot_scan_cnt)); /* preestimate scan count until which scan result this report is going to end */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(siter, snext, ¶ms_batch->get_batch.expired_scan_results_list, list) { + GCC_DIAGNOSTIC_POP(); phead = siter->bestnetheader; while (phead != NULL) { /* if left_size is less than bestheader total size , stop this */ @@ -722,54 +826,57 @@ DHD_PNO(("\n<loop : %d, apcount %d>\n", cnt - 1, phead->tot_cnt)); /* attribute of the scan */ if (phead->reason & PNO_STATUS_ABORT_MASK) { - bp += nreadsize = sprintf(bp, "trunc\n"); + bp += nreadsize = snprintf(bp, nleftsize, "trunc\n"); nleftsize -= nreadsize; } + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, &phead->entry_list, list) { + GCC_DIAGNOSTIC_POP(); t_delta = jiffies_to_msecs(jiffies - iter->recorded_time); #ifdef PNO_DEBUG _base_bp = bp; memset(msg, 0, sizeof(msg)); -#endif +#endif // endif /* BSSID info */ - bp += nreadsize = sprintf(bp, "bssid=%s\n", + bp += nreadsize = snprintf(bp, nleftsize, "bssid=%s\n", bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf)); nleftsize -= nreadsize; /* SSID */ - bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID); + bp += nreadsize = snprintf(bp, nleftsize, "ssid=%s\n", iter->SSID); nleftsize -= nreadsize; /* channel */ - bp += nreadsize = sprintf(bp, "freq=%d\n", + bp += nreadsize = snprintf(bp, nleftsize, "freq=%d\n", wf_channel2mhz(iter->channel, iter->channel <= CH_MAX_2G_CHANNEL? WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); nleftsize -= nreadsize; /* RSSI */ - bp += nreadsize = sprintf(bp, "level=%d\n", iter->RSSI); + bp += nreadsize = snprintf(bp, nleftsize, "level=%d\n", iter->RSSI); nleftsize -= nreadsize; /* add the time consumed in Driver to the timestamp of firmware */ iter->timestamp += t_delta; - bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp); + bp += nreadsize = snprintf(bp, nleftsize, + "age=%d\n", iter->timestamp); nleftsize -= nreadsize; /* RTT0 */ - bp += nreadsize = sprintf(bp, "dist=%d\n", + bp += nreadsize = snprintf(bp, nleftsize, "dist=%d\n", (iter->rtt0 == 0)? -1 : iter->rtt0); nleftsize -= nreadsize; /* RTT1 */ - bp += nreadsize = sprintf(bp, "distSd=%d\n", + bp += nreadsize = snprintf(bp, nleftsize, "distSd=%d\n", (iter->rtt0 == 0)? -1 : iter->rtt1); nleftsize -= nreadsize; - bp += nreadsize = sprintf(bp, "%s", AP_END_MARKER); + bp += nreadsize = snprintf(bp, nleftsize, "%s", AP_END_MARKER); nleftsize -= nreadsize; list_del(&iter->list); MFREE(dhd->osh, iter, BESTNET_ENTRY_SIZE); #ifdef PNO_DEBUG memcpy(msg, _base_bp, bp - _base_bp); DHD_PNO(("Entry : \n%s", msg)); -#endif +#endif // endif } - bp += nreadsize = sprintf(bp, "%s", SCAN_END_MARKER); + bp += nreadsize = snprintf(bp, nleftsize, "%s", SCAN_END_MARKER); DHD_PNO(("%s", SCAN_END_MARKER)); nleftsize -= nreadsize; pprev = phead; @@ -793,9 +900,11 @@ } params_batch->get_batch.expired_tot_scan_cnt -= cnt; /* set FALSE only if the link list is empty after returning the data */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); if (list_empty(¶ms_batch->get_batch.expired_scan_results_list)) { + GCC_DIAGNOSTIC_POP(); params_batch->get_batch.batch_started = FALSE; - bp += sprintf(bp, "%s", RESULTS_END_MARKER); + bp += snprintf(bp, nleftsize, "%s", RESULTS_END_MARKER); DHD_PNO(("%s", RESULTS_END_MARKER)); DHD_PNO(("%s : Getting the batching data is complete\n", __FUNCTION__)); } @@ -815,6 +924,8 @@ NULL_CHECK(head, "head is NULL", err); NULL_CHECK(head->next, "head->next is NULL", err); DHD_PNO(("%s enter\n", __FUNCTION__)); + + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(siter, snext, head, list) { if (only_last) { @@ -843,6 +954,7 @@ MFREE(dhd->osh, siter, SCAN_RESULTS_SIZE); } } + GCC_DIAGNOSTIC_POP(); return removed_scan_cnt; } @@ -892,12 +1004,15 @@ case DHD_PNO_LEGACY_MODE: { struct dhd_pno_ssid *iter, *next; if (params->params_legacy.nssid > 0) { + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, ¶ms->params_legacy.ssid_list, list) { + GCC_DIAGNOSTIC_POP(); list_del(&iter->list); - kfree(iter); + MFREE(dhd->osh, iter, sizeof(struct dhd_pno_ssid)); } } + params->params_legacy.nssid = 0; params->params_legacy.scan_fr = 0; params->params_legacy.pno_freq_expo_max = 0; @@ -935,10 +1050,12 @@ case DHD_PNO_HOTLIST_MODE: { struct dhd_pno_bssid *iter, *next; if (params->params_hotlist.nbssid > 0) { + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, ¶ms->params_hotlist.bssid_list, list) { + GCC_DIAGNOSTIC_POP(); list_del(&iter->list); - kfree(iter); + MFREE(dhd->osh, iter, sizeof(struct dhd_pno_ssid)); } } params->params_hotlist.scan_fr = 0; @@ -974,40 +1091,15 @@ return err; } -#ifdef GSCAN_SUPPORT -static int -_dhd_pno_add_significant_bssid(dhd_pub_t *dhd, - wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid) -{ - int err = BCME_OK; - NULL_CHECK(dhd, "dhd is NULL", err); - - if (!nbssid) { - err = BCME_ERROR; - goto exit; - } - - NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err); - - err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid, - sizeof(wl_pfn_significant_bssid_t) * nbssid, NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err)); - goto exit; - } -exit: - return err; -} -#endif /* GSCAN_SUPPORT */ - int dhd_pno_stop_for_ssid(dhd_pub_t *dhd) { int err = BCME_OK; - uint32 mode = 0; + uint32 mode = 0, cnt = 0; dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - wl_pfn_bssid_t *p_pfn_bssid = NULL; + dhd_pno_params_t *_params = NULL; + wl_pfn_bssid_t *p_pfn_bssid = NULL, *tmp_bssid; + NULL_CHECK(dhd, "dev is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); _pno_state = PNO_GET_PNOSTATE(dhd); @@ -1016,7 +1108,11 @@ goto exit; } DHD_PNO(("%s enter\n", __FUNCTION__)); + /* If pno mode is PNO_LEGACY_MODE clear the pno values and unset the DHD_PNO_LEGACY_MODE */ + _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + #ifdef GSCAN_SUPPORT if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { struct dhd_pno_gscan_params *gscan_params; @@ -1053,7 +1149,14 @@ dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); /* save current pno_mode before calling dhd_pno_clean */ mode = _pno_state->pno_mode; - dhd_pno_clean(dhd); + err = dhd_pno_clean(dhd); + if (err < 0) { + err = BCME_ERROR; + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + /* restore previous pno_mode */ _pno_state->pno_mode = mode; if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { @@ -1070,8 +1173,8 @@ /* restart HOTLIST SCAN */ struct dhd_pno_bssid *iter, *next; _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * - _params->params_hotlist.nbssid, GFP_KERNEL); + p_pfn_bssid = MALLOCZ(dhd->osh, sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid); if (p_pfn_bssid == NULL) { DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" " (count: %d)", @@ -1081,12 +1184,23 @@ goto exit; } /* convert dhd_pno_bssid to wl_pfn_bssid */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); + cnt = 0; + tmp_bssid = p_pfn_bssid; list_for_each_entry_safe(iter, next, &_params->params_hotlist.bssid_list, list) { - memcpy(&p_pfn_bssid->macaddr, + GCC_DIAGNOSTIC_POP(); + memcpy(&tmp_bssid->macaddr, &iter->macaddr, ETHER_ADDR_LEN); - p_pfn_bssid->flags = iter->flags; - p_pfn_bssid++; + tmp_bssid->flags = iter->flags; + if (cnt < _params->params_hotlist.nbssid) { + tmp_bssid++; + cnt++; + } else { + DHD_ERROR(("%s: Allocated insufficient memory\n", + __FUNCTION__)); + break; + } } err = dhd_pno_set_for_hotlist(dhd, p_pfn_bssid, &_params->params_hotlist); if (err < 0) { @@ -1105,7 +1219,10 @@ } } exit: - kfree(p_pfn_bssid); + if (p_pfn_bssid) { + MFREE(dhd->osh, p_pfn_bssid, sizeof(wl_pfn_bssid_t) * + _params->params_hotlist.nbssid); + } return err; } @@ -1118,140 +1235,11 @@ return (_dhd_pno_enable(dhd, enable)); } -static wlc_ssid_ext_t * -dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state) -{ - int err = BCME_OK; - int i; - struct dhd_pno_ssid *iter, *next; - dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; - wlc_ssid_ext_t *p_ssid_list; - - p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) * - _params1->params_legacy.nssid, GFP_KERNEL); - if (p_ssid_list == NULL) { - DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)", - __FUNCTION__, _params1->params_legacy.nssid)); - err = BCME_ERROR; - pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - goto exit; - } - i = 0; - /* convert dhd_pno_ssid to wlc_ssid_ext_t */ - list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) { - p_ssid_list[i].SSID_len = iter->SSID_len; - p_ssid_list[i].hidden = iter->hidden; - p_ssid_list[i].rssi_thresh = iter->rssi_thresh; - memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); - i++; - } -exit: - return p_ssid_list; -} - -#ifdef GSCAN_SUPPORT -static int dhd_epno_set_ssid(dhd_pub_t *dhd, - dhd_pno_status_info_t *pno_state) -{ - int err = BCME_OK; - dhd_epno_params_t *iter, *next; - dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - struct dhd_pno_gscan_params *gscan_params; - wlc_ssid_ext_t ssid_elem; - wl_pfn_ext_list_t *p_ssid_ext_elem = NULL; - uint32 mem_needed = 0, i = 0; - uint16 num_visible_epno_ssid; - uint8 flags; - - gscan_params = &_params1->params_gscan; - num_visible_epno_ssid = gscan_params->num_visible_epno_ssid; - - if (num_visible_epno_ssid) { - mem_needed = sizeof(wl_pfn_ext_list_t) + (sizeof(wl_pfn_ext_t) * - (num_visible_epno_ssid - 1)); - p_ssid_ext_elem = kzalloc(mem_needed, GFP_KERNEL); - if (p_ssid_ext_elem == NULL) { - DHD_ERROR(("%s : failed to allocate memory %u\n", - __FUNCTION__, mem_needed)); - err = BCME_NOMEM; - goto exit; - } - p_ssid_ext_elem->version = PFN_SSID_EXT_VERSION; - p_ssid_ext_elem->count = num_visible_epno_ssid; - } - - DHD_ERROR(("Total ssids %d, visible SSIDs %d\n", gscan_params->num_epno_ssid, - num_visible_epno_ssid)); - - /* convert dhd_pno_ssid to wlc_ssid_ext_t */ - list_for_each_entry_safe(iter, next, &gscan_params->epno_ssid_list, list) { - if (iter->flags & DHD_PNO_USE_SSID) { - memset(&ssid_elem, 0, sizeof(ssid_elem)); - ssid_elem.SSID_len = iter->ssid_len; - ssid_elem.hidden = TRUE; - flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? - WL_PFN_SSID_A_BAND_TRIG: 0; - flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? - WL_PFN_SSID_BG_BAND_TRIG: 0; - ssid_elem.flags = flags; - ssid_elem.rssi_thresh = iter->rssi_thresh; - memcpy(ssid_elem.SSID, iter->ssid, iter->ssid_len); - if ((err = _dhd_pno_add_ssid(dhd, &ssid_elem, 1)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); - goto exit; - } - } else if (i < num_visible_epno_ssid) { - p_ssid_ext_elem->pfn_ext[i].rssi_thresh = iter->rssi_thresh; - switch (iter->auth) { - case DHD_PNO_AUTH_CODE_OPEN: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = WPA_AUTH_DISABLED; - break; - case DHD_PNO_AUTH_CODE_PSK: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (WPA2_AUTH_PSK | WPA_AUTH_PSK); - break; - case DHD_PNO_AUTH_CODE_EAPOL: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (uint16)WPA_AUTH_PFN_ANY; - break; - default: - p_ssid_ext_elem->pfn_ext[i].wpa_auth = - (uint16)WPA_AUTH_PFN_ANY; - break; - } - memcpy(p_ssid_ext_elem->pfn_ext[i].ssid, iter->ssid, iter->ssid_len); - p_ssid_ext_elem->pfn_ext[i].ssid_len = iter->ssid_len; - iter->index = gscan_params->ssid_ext_last_used_index++; - flags = (iter->flags & DHD_EPNO_A_BAND_TRIG) ? - WL_PFN_SSID_A_BAND_TRIG: 0; - flags |= (iter->flags & DHD_EPNO_BG_BAND_TRIG) ? - WL_PFN_SSID_BG_BAND_TRIG: 0; - p_ssid_ext_elem->pfn_ext[i].flags = flags; - DHD_ERROR(("SSID %s idx %d rssi thresh %d flags %x\n", iter->ssid, - iter->index, iter->rssi_thresh, flags)); - i++; - } - } - if (num_visible_epno_ssid) { - err = dhd_iovar(dhd, 0, "pfn_add_ssid_ext", (char *)p_ssid_ext_elem, - mem_needed, NULL, 0, TRUE); - - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_add_pno_ext_ssid %d\n", __FUNCTION__, - err)); - } - } -exit: - kfree(p_ssid_ext_elem); - return err; -} -#endif /* GSCAN_SUPPORT */ - static int -dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list, - int nssid) +dhd_pno_add_to_ssid_list(dhd_pub_t *dhd, struct list_head *ptr, wlc_ssid_ext_t *ssid_list, + int nssid, int *num_ssid_added) { - int ret = 0; + int ret = BCME_OK; int i; struct dhd_pno_ssid *_pno_ssid; @@ -1262,7 +1250,14 @@ ret = BCME_ERROR; goto exit; } - _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); + /* Check for broadcast ssid */ + if (!ssid_list[i].SSID_len) { + DHD_ERROR(("%d: Broadcast SSID is illegal for PNO setting\n", i)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid = (struct dhd_pno_ssid *)MALLOCZ(dhd->osh, + sizeof(struct dhd_pno_ssid)); if (_pno_ssid == NULL) { DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", __FUNCTION__)); @@ -1272,12 +1267,15 @@ _pno_ssid->SSID_len = ssid_list[i].SSID_len; _pno_ssid->hidden = ssid_list[i].hidden; _pno_ssid->rssi_thresh = ssid_list[i].rssi_thresh; + _pno_ssid->flags = ssid_list[i].flags; + _pno_ssid->wpa_auth = WPA_AUTH_PFN_ANY; + memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); - list_add_tail(&_pno_ssid->list, ¶ms->params_legacy.ssid_list); - params->params_legacy.nssid++; + list_add_tail(&_pno_ssid->list, ptr); } exit: + *num_ssid_added = i; return ret; } @@ -1285,25 +1283,63 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) { + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + struct dhd_pno_legacy_params *params_legacy; + int err = BCME_OK; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("%s: PNO Not enabled/Not ready\n", __FUNCTION__)); + return BCME_NOTREADY; + } + + if (!dhd_support_sta_mode(dhd)) { + return BCME_BADOPTION; + } + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); + params_legacy = &(_params->params_legacy); + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + + if (err < 0) { + DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", + __FUNCTION__, err)); + return err; + } + + INIT_LIST_HEAD(¶ms_legacy->ssid_list); + + if (dhd_pno_add_to_ssid_list(dhd, ¶ms_legacy->ssid_list, ssid_list, + nssid, ¶ms_legacy->nssid) < 0) { + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + return BCME_ERROR; + } + + DHD_PNO(("%s enter : nssid %d, scan_fr :%d, pno_repeat :%d," + "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, + params_legacy->nssid, scan_fr, pno_repeat, pno_freq_expo_max, nchan)); + + return dhd_pno_set_legacy_pno(dhd, scan_fr, pno_repeat, + pno_freq_expo_max, channel_list, nchan); + +} + +static int +dhd_pno_set_legacy_pno(dhd_pub_t *dhd, uint16 scan_fr, int pno_repeat, + int pno_freq_expo_max, uint16 *channel_list, int nchan) +{ dhd_pno_params_t *_params; dhd_pno_params_t *_params2; dhd_pno_status_info_t *_pno_state; uint16 _chan_list[WL_NUMCHANNELS]; int32 tot_nchan = 0; int err = BCME_OK; - int i; + int i, nssid; int mode = 0; - NULL_CHECK(dhd, "dhd is NULL", err); - NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); - _pno_state = PNO_GET_PNOSTATE(dhd); + struct list_head *ssid_list; - if (!dhd_support_sta_mode(dhd)) { - err = BCME_BADOPTION; - goto exit_no_clear; - } - DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," - "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, - scan_fr, pno_repeat, pno_freq_expo_max, nchan)); + _pno_state = PNO_GET_PNOSTATE(dhd); _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); /* If GSCAN is also ON will handle this down below */ @@ -1311,7 +1347,7 @@ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE && !(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) { #else - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { #endif /* GSCAN_SUPPORT */ DHD_ERROR(("%s : Legacy PNO mode was already started, " "will disable previous one to start new one\n", __FUNCTION__)); @@ -1319,16 +1355,10 @@ if (err < 0) { DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", __FUNCTION__, err)); - goto exit_no_clear; + return err; } } _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); - if (err < 0) { - DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", - __FUNCTION__, err)); - goto exit_no_clear; - } memset(_chan_list, 0, sizeof(_chan_list)); tot_nchan = MIN(nchan, WL_NUMCHANNELS); if (tot_nchan > 0 && channel_list) { @@ -1339,13 +1369,13 @@ else { tot_nchan = WL_NUMCHANNELS; err = _dhd_pno_get_channels(dhd, _chan_list, &tot_nchan, - (WLC_BAND_2G | WLC_BAND_5G), FALSE); + (WLC_BAND_2G | WLC_BAND_5G), FALSE); if (err < 0) { tot_nchan = 0; DHD_PNO(("Could not get channel list for PNO SSID\n")); } else { for (i = 0; i < tot_nchan; i++) - _params->params_legacy.chan_list[i] = _chan_list[i]; + _params->params_legacy.chan_list[i] = _chan_list[i]; } } #endif /* GSCAN_SUPPORT */ @@ -1359,7 +1389,7 @@ err = _dhd_pno_enable(dhd, PNO_OFF); if (err < 0) { DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit_no_clear; + goto exit; } /* restore the previous mode */ _pno_state->pno_mode = mode; @@ -1375,7 +1405,7 @@ DHD_ERROR(("%s : failed to merge channel list" " between legacy and batch\n", __FUNCTION__)); - goto exit_no_clear; + goto exit; } } else { DHD_PNO(("superset channel will use" @@ -1392,7 +1422,7 @@ DHD_ERROR(("%s : failed to merge channel list" " between legacy and hotlist\n", __FUNCTION__)); - goto exit_no_clear; + goto exit; } } } @@ -1401,13 +1431,18 @@ _params->params_legacy.pno_repeat = pno_repeat; _params->params_legacy.pno_freq_expo_max = pno_freq_expo_max; _params->params_legacy.nchan = tot_nchan; - _params->params_legacy.nssid = 0; - INIT_LIST_HEAD(&_params->params_legacy.ssid_list); + ssid_list = &_params->params_legacy.ssid_list; + nssid = _params->params_legacy.nssid; + #ifdef GSCAN_SUPPORT /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { - if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { - err = BCME_ERROR; + struct dhd_pno_gscan_params *gscan_params; + gscan_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan; + /* ePNO and Legacy PNO do not co-exist */ + if (gscan_params->epno_cfg.num_epno_ssid) { + DHD_PNO(("ePNO and Legacy PNO do not co-exist\n")); + err = BCME_EPERM; goto exit; } DHD_PNO(("GSCAN mode is ON! Will restart GSCAN+Legacy PNO\n")); @@ -1421,10 +1456,6 @@ } if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); - goto exit; - } - if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { - err = BCME_ERROR; goto exit; } if (tot_nchan > 0) { @@ -1442,7 +1473,6 @@ if (err < 0) { _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); } -exit_no_clear: /* clear mode in case of error */ if (err < 0) { int ret = dhd_pno_clean(dhd); @@ -1466,7 +1496,6 @@ dhd_pno_params_t *_params; dhd_pno_params_t *_params2; dhd_pno_status_info_t *_pno_state; - wlc_ssid_ext_t *p_ssid_list = NULL; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); NULL_CHECK(batch_params, "batch_params is NULL", err); @@ -1529,7 +1558,7 @@ } DHD_PNO(("\n")); } -#endif +#endif // endif if (_params->params_batch.nchan) { /* copy the channel list into local array */ memcpy(_chan_list, _params->params_batch.chan_list, sizeof(_chan_list)); @@ -1562,14 +1591,8 @@ } else { DHD_PNO(("superset channel will use all channels in firmware\n")); } - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, - _params2->params_legacy.nssid)) < 0) { + if ((err = _dhd_pno_add_ssid(dhd, &_params2->params_legacy.ssid_list, + _params2->params_legacy.nssid)) < 0) { DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); goto exit; } @@ -1601,18 +1624,84 @@ /* return #max scan firmware can do */ err = mscan; } - if (p_ssid_list) - kfree(p_ssid_list); return err; } - #ifdef GSCAN_SUPPORT + +static int +dhd_set_epno_params(dhd_pub_t *dhd, wl_ssid_ext_params_t *params, bool set) +{ + wl_pfn_ssid_cfg_t cfg; + int err; + NULL_CHECK(dhd, "dhd is NULL\n", err); + memset(&cfg, 0, sizeof(wl_pfn_ssid_cfg_t)); + cfg.version = WL_PFN_SSID_CFG_VERSION; + + /* If asked to clear params (set == FALSE) just set the CLEAR bit */ + if (!set) + cfg.flags |= WL_PFN_SSID_CFG_CLEAR; + else if (params) + memcpy(&cfg.params, params, sizeof(wl_ssid_ext_params_t)); + err = dhd_iovar(dhd, 0, "pfn_ssid_cfg", (char *)&cfg, + sizeof(wl_pfn_ssid_cfg_t), NULL, 0, TRUE); + if (err != BCME_OK) { + DHD_ERROR(("%s : Failed to execute pfn_ssid_cfg %d\n", __FUNCTION__, err)); + } + return err; +} + +int +dhd_pno_flush_fw_epno(dhd_pub_t *dhd) +{ + int err; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + + err = dhd_set_epno_params(dhd, NULL, FALSE); + if (err < 0) { + DHD_ERROR(("failed to set ePNO params %d\n", err)); + return err; + } + err = _dhd_pno_flush_ssid(dhd); + return err; +} + +int +dhd_pno_set_epno(dhd_pub_t *dhd) +{ + int err = BCME_OK; + dhd_pno_params_t *params; + dhd_pno_status_info_t *_pno_state; + + struct dhd_pno_gscan_params *gscan_params; + + NULL_CHECK(dhd, "dhd is NULL\n", err); + NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + _pno_state = PNO_GET_PNOSTATE(dhd); + params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + gscan_params = ¶ms->params_gscan; + + if (gscan_params->epno_cfg.num_epno_ssid) { + DHD_PNO(("num_epno_ssid %d\n", gscan_params->epno_cfg.num_epno_ssid)); + if ((err = _dhd_pno_add_ssid(dhd, &gscan_params->epno_cfg.epno_ssid_list, + gscan_params->epno_cfg.num_epno_ssid)) < 0) { + DHD_ERROR(("failed to add ssid list (err %d) to firmware\n", err)); + return err; + } + err = dhd_set_epno_params(dhd, &gscan_params->epno_cfg.params, TRUE); + if (err < 0) { + DHD_ERROR(("failed to set ePNO params %d\n", err)); + } + } + return err; +} + static void -dhd_pno_reset_cfg_gscan(dhd_pno_params_t *_params, +dhd_pno_reset_cfg_gscan(dhd_pub_t *dhd, dhd_pno_params_t *_params, dhd_pno_status_info_t *_pno_state, uint8 flags) { - DHD_ERROR(("%s enter\n", __FUNCTION__)); + DHD_PNO(("%s enter\n", __FUNCTION__)); if (flags & GSCAN_FLUSH_SCAN_CFG) { _params->params_gscan.bestn = 0; @@ -1629,41 +1718,32 @@ if (flags & GSCAN_FLUSH_HOTLIST_CFG) { struct dhd_pno_bssid *iter, *next; if (_params->params_gscan.nbssid_hotlist > 0) { + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, &_params->params_gscan.hotlist_bssid_list, list) { + GCC_DIAGNOSTIC_POP(); list_del(&iter->list); - kfree(iter); + MFREE(dhd->osh, iter, sizeof(struct dhd_pno_bssid)); } } _params->params_gscan.nbssid_hotlist = 0; DHD_PNO(("Flush Hotlist Config\n")); } - if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) { - dhd_pno_significant_bssid_t *iter, *next; - - if (_params->params_gscan.nbssid_significant_change > 0) { - list_for_each_entry_safe(iter, next, - &_params->params_gscan.significant_bssid_list, list) { - list_del(&iter->list); - kfree(iter); - } - } - _params->params_gscan.nbssid_significant_change = 0; - DHD_PNO(("Flush Significant Change Config\n")); - } if (flags & GSCAN_FLUSH_EPNO_CFG) { - dhd_epno_params_t *iter, *next; + dhd_pno_ssid_t *iter, *next; + dhd_epno_ssid_cfg_t *epno_cfg = &_params->params_gscan.epno_cfg; - if (_params->params_gscan.num_epno_ssid > 0) { + if (epno_cfg->num_epno_ssid > 0) { + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, - &_params->params_gscan.epno_ssid_list, list) { + &epno_cfg->epno_ssid_list, list) { + GCC_DIAGNOSTIC_POP(); list_del(&iter->list); - kfree(iter); + MFREE(dhd->osh, iter, sizeof(struct dhd_pno_bssid)); } + epno_cfg->num_epno_ssid = 0; } - _params->params_gscan.num_epno_ssid = 0; - _params->params_gscan.num_visible_epno_ssid = 0; - _params->params_gscan.ssid_ext_last_used_index = 0; + memset(&epno_cfg->params, 0, sizeof(wl_ssid_ext_params_t)); DHD_PNO(("Flushed ePNO Config\n")); } @@ -1739,162 +1819,9 @@ return err; } -static void * -dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) -{ - gscan_results_cache_t *iter, *results; - dhd_pno_status_info_t *_pno_state; - dhd_pno_params_t *_params; - uint16 num_scan_ids = 0, num_results = 0; - - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - - iter = results = _params->params_gscan.gscan_batch_cache; - while (iter) { - num_results += iter->tot_count - iter->tot_consumed; - num_scan_ids++; - iter = iter->next; - } - - *len = ((num_results << 16) | (num_scan_ids)); - return results; -} - -void * -dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *info, uint32 *len) -{ - void *ret = NULL; - dhd_pno_gscan_capabilities_t *ptr; - dhd_epno_params_t *epno_params; - dhd_pno_params_t *_params; - dhd_pno_status_info_t *_pno_state; - - if (!dhd || !dhd->pno_state) { - DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); - return NULL; - } - _pno_state = PNO_GET_PNOSTATE(dhd); - _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - if (!len) { - DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); - return NULL; - } - switch (type) { - case DHD_PNO_GET_CAPABILITIES: - ptr = (dhd_pno_gscan_capabilities_t *) - kmalloc(sizeof(dhd_pno_gscan_capabilities_t), GFP_KERNEL); - if (!ptr) - break; - /* Hardcoding these values for now, need to get - * these values from FW, will change in a later check-in - */ - ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; - ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; - ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; - ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; - ptr->max_scan_reporting_threshold = 100; - ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS; - ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS; - ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; - ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; - ptr->max_white_list_ssid = MAX_WHITELIST_SSID; - ret = (void *)ptr; - *len = sizeof(dhd_pno_gscan_capabilities_t); - break; - - case DHD_PNO_GET_BATCH_RESULTS: - ret = dhd_get_gscan_batch_results(dhd, len); - break; - case DHD_PNO_GET_CHANNEL_LIST: - if (info) { - uint16 ch_list[WL_NUMCHANNELS]; - uint32 *ptr, mem_needed, i; - int32 err, nchan = WL_NUMCHANNELS; - uint32 *gscan_band = (uint32 *) info; - uint8 band = 0; - - /* No band specified?, nothing to do */ - if ((*gscan_band & GSCAN_BAND_MASK) == 0) { - DHD_PNO(("No band specified\n")); - *len = 0; - break; - } - - /* HAL and DHD use different bits for 2.4G and - * 5G in bitmap. Hence translating it here... - */ - if (*gscan_band & GSCAN_BG_BAND_MASK) { - band |= WLC_BAND_2G; - } - if (*gscan_band & GSCAN_A_BAND_MASK) { - band |= WLC_BAND_5G; - } - - err = _dhd_pno_get_channels(dhd, ch_list, &nchan, - (band & GSCAN_ABG_BAND_MASK), - !(*gscan_band & GSCAN_DFS_MASK)); - - if (err < 0) { - DHD_ERROR(("%s: failed to get valid channel list\n", - __FUNCTION__)); - *len = 0; - } else { - mem_needed = sizeof(uint32) * nchan; - ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL); - if (!ptr) { - DHD_ERROR(("%s: Unable to malloc %d bytes\n", - __FUNCTION__, mem_needed)); - break; - } - for (i = 0; i < nchan; i++) { - ptr[i] = wf_channel2mhz(ch_list[i], - (ch_list[i] <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - } - ret = ptr; - *len = mem_needed; - } - } else { - *len = 0; - DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); - } - break; - case DHD_PNO_GET_EPNO_SSID_ELEM: - if (_params->params_gscan.num_epno_ssid >= - (MAX_EPNO_SSID_NUM + MAX_EPNO_HIDDEN_SSID)) { - DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", - _params->params_gscan.num_epno_ssid)); - return NULL; - } - - if (!_params->params_gscan.num_epno_ssid) - INIT_LIST_HEAD(&_params->params_gscan.epno_ssid_list); - - epno_params = kzalloc(sizeof(dhd_epno_params_t), GFP_KERNEL); - if (!epno_params) { - DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", - sizeof(dhd_epno_params_t))); - return NULL; - } - _params->params_gscan.num_epno_ssid++; - epno_params->index = DHD_EPNO_DEFAULT_INDEX; - list_add_tail(&epno_params->list, &_params->params_gscan.epno_ssid_list); - ret = epno_params; - break; - default: - DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); - break; - } - - return ret; - -} - int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, - void *buf, uint8 flush) + void *buf, bool flush) { int err = BCME_OK; dhd_pno_params_t *_params; @@ -1911,22 +1838,23 @@ mutex_lock(&_pno_state->pno_mutex); switch (type) { - case DHD_PNO_BATCH_SCAN_CFG_ID: + case DHD_PNO_BATCH_SCAN_CFG_ID: { gscan_batch_params_t *ptr = (gscan_batch_params_t *)buf; _params->params_gscan.bestn = ptr->bestn; _params->params_gscan.mscan = ptr->mscan; _params->params_gscan.buffer_threshold = ptr->buffer_threshold; - break; } + break; case DHD_PNO_GEOFENCE_SCAN_CFG_ID: { gscan_hotlist_scan_params_t *ptr = (gscan_hotlist_scan_params_t *)buf; struct dhd_pno_bssid *_pno_bssid; struct bssid_t *bssid_ptr; int8 flags; + if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, + dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state, GSCAN_FLUSH_HOTLIST_CFG); } @@ -1936,18 +1864,19 @@ if (!_params->params_gscan.nbssid_hotlist) { INIT_LIST_HEAD(&_params->params_gscan.hotlist_bssid_list); } + if ((_params->params_gscan.nbssid_hotlist + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { + ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { DHD_ERROR(("Excessive number of hotlist APs programmed %d\n", - (_params->params_gscan.nbssid_hotlist + - ptr->nbssid))); + (_params->params_gscan.nbssid_hotlist + + ptr->nbssid))); err = BCME_RANGE; goto exit; } for (i = 0, bssid_ptr = ptr->bssid; i < ptr->nbssid; i++, bssid_ptr++) { - _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); - + _pno_bssid = (struct dhd_pno_bssid *)MALLOCZ(dhd->osh, + sizeof(struct dhd_pno_bssid)); if (!_pno_bssid) { DHD_ERROR(("_pno_bssid is NULL, cannot kalloc %zd bytes", sizeof(struct dhd_pno_bssid))); @@ -1964,65 +1893,11 @@ _params->params_gscan.nbssid_hotlist += ptr->nbssid; _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - break; } - case DHD_PNO_SIGNIFICANT_SCAN_CFG_ID: + break; + case DHD_PNO_SCAN_CFG_ID: { - gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf; - dhd_pno_significant_bssid_t *_pno_significant_change_bssid; - wl_pfn_significant_bssid_t *significant_bssid_ptr; - - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_SIGNIFICANT_CFG); - } - - if (!ptr->nbssid) { - break; - } - if (!_params->params_gscan.nbssid_significant_change) { - INIT_LIST_HEAD(&_params->params_gscan.significant_bssid_list); - } - if ((_params->params_gscan.nbssid_significant_change + - ptr->nbssid) > PFN_SWC_MAX_NUM_APS) { - DHD_ERROR(("Excessive number of SWC APs programmed %d\n", - (_params->params_gscan.nbssid_significant_change + - ptr->nbssid))); - err = BCME_RANGE; - goto exit; - } - - for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list; - i < ptr->nbssid; i++, significant_bssid_ptr++) { - _pno_significant_change_bssid = - kzalloc(sizeof(dhd_pno_significant_bssid_t), - GFP_KERNEL); - - if (!_pno_significant_change_bssid) { - DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc %zd bytes", - sizeof(dhd_pno_significant_bssid_t))); - err = BCME_NOMEM; - goto exit; - } - memcpy(&_pno_significant_change_bssid->BSSID, - &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN); - _pno_significant_change_bssid->rssi_low_threshold = - significant_bssid_ptr->rssi_low_threshold; - _pno_significant_change_bssid->rssi_high_threshold = - significant_bssid_ptr->rssi_high_threshold; - list_add_tail(&_pno_significant_change_bssid->list, - &_params->params_gscan.significant_bssid_list); - } - - _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold; - _params->params_gscan.swc_rssi_window_size = ptr->rssi_window; - _params->params_gscan.lost_ap_window = ptr->lost_ap_window; - _params->params_gscan.nbssid_significant_change += ptr->nbssid; - break; - } - case DHD_PNO_SCAN_CFG_ID: - { - int i, k; + int k; uint16 band; gscan_scan_params_t *ptr = (gscan_scan_params_t *)buf; struct dhd_pno_gscan_channel_bucket *ch_bucket; @@ -2046,13 +1921,15 @@ /* HAL and DHD use different bits for 2.4G and * 5G in bitmap. Hence translating it here... */ - if (band & GSCAN_BG_BAND_MASK) + if (band & GSCAN_BG_BAND_MASK) { ch_bucket[i].band |= WLC_BAND_2G; - if (band & GSCAN_A_BAND_MASK) + } + if (band & GSCAN_A_BAND_MASK) { ch_bucket[i].band |= WLC_BAND_5G; - if (band & GSCAN_DFS_MASK) + } + if (band & GSCAN_DFS_MASK) { ch_bucket[i].band |= GSCAN_DFS_MASK; - + } DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band, ch_bucket[i].report_flag)); } @@ -2063,8 +1940,8 @@ ch_bucket[i].bucket_max_multiple = ch_bucket[i].bucket_max_multiple/ptr->scan_fr; DHD_PNO(("mult %d max_mult %d\n", - ch_bucket[i].bucket_freq_multiple, - ch_bucket[i].bucket_max_multiple)); + ch_bucket[i].bucket_freq_multiple, + ch_bucket[i].bucket_max_multiple)); } _params->params_gscan.scan_fr = ptr->scan_fr; @@ -2073,27 +1950,34 @@ } else { err = BCME_BADARG; } - break; - } - case DHD_PNO_EPNO_CFG_ID: - if (flush) { - dhd_pno_reset_cfg_gscan(_params, _pno_state, - GSCAN_FLUSH_EPNO_CFG); - } else { - _params->params_gscan.num_visible_epno_ssid += *((uint16 *)buf); } break; - default: - err = BCME_BADARG; - DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); - break; + case DHD_PNO_EPNO_CFG_ID: + if (flush) { + dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state, + GSCAN_FLUSH_EPNO_CFG); + } + break; + case DHD_PNO_EPNO_PARAMS_ID: + if (flush) { + memset(&_params->params_gscan.epno_cfg.params, 0, + sizeof(wl_ssid_ext_params_t)); + } + if (buf) { + memcpy(&_params->params_gscan.epno_cfg.params, buf, + sizeof(wl_ssid_ext_params_t)); + } + break; + default: + err = BCME_BADARG; + DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); + break; } exit: mutex_unlock(&_pno_state->pno_mutex); return err; } - static bool validate_gscan_params(struct dhd_pno_gscan_params *gscan_params) @@ -2125,20 +2009,17 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params) { int err = BCME_OK; - int mode, i = 0, k; + int mode, i = 0; uint16 _chan_list[WL_NUMCHANNELS]; int tot_nchan = 0; int num_buckets_to_fw, tot_num_buckets, gscan_param_size = 0; dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket = NULL; wl_pfn_gscan_cfg_t *pfn_gscan_cfg_t = NULL; - wl_pfn_significant_bssid_t *p_pfn_significant_bssid = NULL; wl_pfn_bssid_t *p_pfn_bssid = NULL; - wlc_ssid_ext_t *pssid_list = NULL; - dhd_pno_params_t *params_legacy; dhd_pno_params_t *_params; + bool fw_flushed = FALSE; - params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); @@ -2161,7 +2042,7 @@ err = BCME_BADARG; goto exit; } - /* Create channel list based on channel buckets */ + if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state, _chan_list, &tot_num_buckets, &num_buckets_to_fw))) { goto exit; @@ -2181,23 +2062,21 @@ mutex_unlock(&_pno_state->pno_mutex); goto exit; } + fw_flushed = TRUE; /* restore the previous mode */ _pno_state->pno_mode = mode; } _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE; mutex_unlock(&_pno_state->pno_mutex); - if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && + !gscan_params->epno_cfg.num_epno_ssid) { + struct dhd_pno_legacy_params *params_legacy; + params_legacy = + &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - if (!pssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - - if ((err = _dhd_pno_add_ssid(dhd, pssid_list, - params_legacy->params_legacy.nssid)) < 0) { + if ((err = _dhd_pno_add_ssid(dhd, ¶ms_legacy->ssid_list, + params_legacy->nssid)) < 0) { DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); goto exit; } @@ -2210,7 +2089,7 @@ gscan_param_size = sizeof(wl_pfn_gscan_cfg_t) + (num_buckets_to_fw - 1) * sizeof(wl_pfn_gscan_ch_bucket_cfg_t); - pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(dhd->osh, gscan_param_size); + pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOCZ(dhd->osh, gscan_param_size); if (!pfn_gscan_cfg_t) { DHD_ERROR(("%s: failed to malloc memory of size %d\n", @@ -2220,40 +2099,28 @@ } pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION; - if (gscan_params->mscan) { + if (gscan_params->mscan) pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold; - } else { + else pfn_gscan_cfg_t->buffer_threshold = GSCAN_BATCH_NO_THR_SET; - } - if (gscan_params->nbssid_significant_change) { - pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold; - pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size; - pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window; - } else { - pfn_gscan_cfg_t->swc_nbssid_threshold = 0; - pfn_gscan_cfg_t->swc_rssi_window_size = 0; - pfn_gscan_cfg_t->lost_ap_window = 0; - } pfn_gscan_cfg_t->flags = (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK); + pfn_gscan_cfg_t->flags |= GSCAN_ALL_BUCKETS_IN_FIRST_SCAN_MASK; pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw; pfn_gscan_cfg_t->retry_threshold = GSCAN_RETRY_THRESHOLD; - for (i = 0, k = 0; i < tot_num_buckets; i++) { - if (ch_bucket[i].bucket_end_index != CHANNEL_BUCKET_EMPTY_INDEX) { - pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index = - ch_bucket[i].bucket_end_index; - pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple = - ch_bucket[i].bucket_freq_multiple; - pfn_gscan_cfg_t->channel_bucket[k].max_freq_multiple = - ch_bucket[i].max_freq_multiple; - pfn_gscan_cfg_t->channel_bucket[k].repeat = - ch_bucket[i].repeat; - pfn_gscan_cfg_t->channel_bucket[k].flag = - ch_bucket[i].flag; - k++; - } + for (i = 0; i < num_buckets_to_fw; i++) { + pfn_gscan_cfg_t->channel_bucket[i].bucket_end_index = + ch_bucket[i].bucket_end_index; + pfn_gscan_cfg_t->channel_bucket[i].bucket_freq_multiple = + ch_bucket[i].bucket_freq_multiple; + pfn_gscan_cfg_t->channel_bucket[i].max_freq_multiple = + ch_bucket[i].max_freq_multiple; + pfn_gscan_cfg_t->channel_bucket[i].repeat = + ch_bucket[i].repeat; + pfn_gscan_cfg_t->channel_bucket[i].flag = + ch_bucket[i].flag; } tot_nchan = pfn_gscan_cfg_t->channel_bucket[num_buckets_to_fw - 1].bucket_end_index + 1; @@ -2271,43 +2138,16 @@ __FUNCTION__, err)); goto exit; } - if (gscan_params->nbssid_significant_change) { - dhd_pno_significant_bssid_t *iter, *next; - - p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change, GFP_KERNEL); - if (p_pfn_significant_bssid == NULL) { - DHD_ERROR(("%s : failed to allocate memory %zd\n", - __FUNCTION__, - sizeof(wl_pfn_significant_bssid_t) * - gscan_params->nbssid_significant_change)); - err = BCME_NOMEM; - goto exit; - } - i = 0; - /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */ - list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) { - p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold; - p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold; - memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN); - i++; - } - DHD_PNO(("nbssid_significant_change %d \n", - gscan_params->nbssid_significant_change)); - err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid, - gscan_params->nbssid_significant_change); - if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n", - __FUNCTION__, err)); - goto exit; - } + /* Reprogram ePNO cfg from dhd cache if FW has been flushed */ + if (fw_flushed) { + dhd_pno_set_epno(dhd); } if (gscan_params->nbssid_hotlist) { struct dhd_pno_bssid *iter, *next; wl_pfn_bssid_t *ptr; - p_pfn_bssid = (wl_pfn_bssid_t *)kzalloc(sizeof(wl_pfn_bssid_t) * - gscan_params->nbssid_hotlist, GFP_KERNEL); + p_pfn_bssid = (wl_pfn_bssid_t *)MALLOCZ(dhd->osh, + sizeof(wl_pfn_bssid_t) * gscan_params->nbssid_hotlist); if (p_pfn_bssid == NULL) { DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" " (count: %d)", @@ -2319,10 +2159,15 @@ ptr = p_pfn_bssid; /* convert dhd_pno_bssid to wl_pfn_bssid */ DHD_PNO(("nhotlist %d\n", gscan_params->nbssid_hotlist)); + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, &gscan_params->hotlist_bssid_list, list) { + char buffer_hotlist[64]; + GCC_DIAGNOSTIC_POP(); memcpy(&ptr->macaddr, &iter->macaddr, ETHER_ADDR_LEN); + BCM_REFERENCE(buffer_hotlist); + DHD_PNO(("%s\n", bcm_ether_ntoa(&ptr->macaddr, buffer_hotlist))); ptr->flags = iter->flags; ptr++; } @@ -2331,15 +2176,6 @@ if (err < 0) { DHD_ERROR(("%s : failed to call _dhd_pno_add_bssid(err :%d)\n", __FUNCTION__, err)); - goto exit; - } - } - - if (gscan_params->num_epno_ssid > 0) { - DHD_ERROR(("num_epno_ssid %d\n", gscan_params->num_epno_ssid)); - err = dhd_epno_set_ssid(dhd, _pno_state); - if (err < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); goto exit; } } @@ -2360,9 +2196,8 @@ _pno_state->pno_mode &= ~DHD_PNO_GSCAN_MODE; } } - kfree(pssid_list); - kfree(p_pfn_significant_bssid); - kfree(p_pfn_bssid); + MFREE(dhd->osh, p_pfn_bssid, + sizeof(wl_pfn_bssid_t) * gscan_params->nbssid_hotlist); if (pfn_gscan_cfg_t) { MFREE(dhd->osh, pfn_gscan_cfg_t, gscan_param_size); } @@ -2385,12 +2220,16 @@ uint16 *ptr = chan_list, max; wl_pfn_gscan_ch_bucket_cfg_t *ch_bucket; dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; - bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE; + bool is_pno_legacy_running; dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket; + + /* ePNO and Legacy PNO do not co-exist */ + is_pno_legacy_running = ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) && + !_params->params_gscan.epno_cfg.num_epno_ssid); if (is_pno_legacy_running) *num_buckets = _params->params_gscan.nchannel_buckets + 1; - else + else *num_buckets = _params->params_gscan.nchannel_buckets; *num_buckets_to_fw = 0; @@ -2463,7 +2302,7 @@ /* If no space is left then only gscan buckets will be sent to FW */ if (nchan) { common_freq = gcd(_params->params_gscan.scan_fr, - _params1->params_legacy.scan_fr); + _params1->params_legacy.scan_fr); max = gscan_buckets[0].bucket_freq_multiple; /* GSCAN buckets */ for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) { @@ -2474,11 +2313,11 @@ } /* Legacy PNO bucket */ ch_bucket[legacy_bucket_idx].bucket_freq_multiple = - _params1->params_legacy.scan_fr; + _params1->params_legacy.scan_fr; ch_bucket[legacy_bucket_idx].bucket_freq_multiple /= - common_freq; + common_freq; _params->params_gscan.max_ch_bucket_freq = MAX(max, - ch_bucket[legacy_bucket_idx].bucket_freq_multiple); + ch_bucket[legacy_bucket_idx].bucket_freq_multiple); ch_bucket[legacy_bucket_idx].flag = CH_BUCKET_REPORT_REGULAR; /* Now add channels to the legacy scan bucket */ for (i = 0; i < _params1->params_legacy.nchan && nchan; i++, nchan--) { @@ -2488,8 +2327,8 @@ ch_bucket[legacy_bucket_idx].bucket_end_index = num_channels - 1; *num_buckets_to_fw = *num_buckets_to_fw + 1; DHD_PNO(("end_idx %d freq_mult - %d\n", - ch_bucket[legacy_bucket_idx].bucket_end_index, - ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); + ch_bucket[legacy_bucket_idx].bucket_end_index, + ch_bucket[legacy_bucket_idx].bucket_freq_multiple)); } } return ch_bucket; @@ -2501,7 +2340,6 @@ int err = BCME_OK; int mode; dhd_pno_status_info_t *_pno_state; - wlc_ssid_ext_t *pssid_list = NULL; _pno_state = PNO_GET_PNOSTATE(dhd); DHD_PNO(("%s enter\n", __FUNCTION__)); @@ -2538,7 +2376,6 @@ } _pno_state->pno_mode = mode; mutex_unlock(&_pno_state->pno_mutex); - _pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan.ssid_ext_last_used_index = 0; /* Reprogram Legacy PNO if it was running */ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { @@ -2547,20 +2384,13 @@ params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; - pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!pssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } DHD_PNO(("Restarting Legacy PNO SSID scan...\n")); memcpy(chan_list, params_legacy->chan_list, - (params_legacy->nchan * sizeof(uint16))); - err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid, - params_legacy->scan_fr, params_legacy->pno_repeat, - params_legacy->pno_freq_expo_max, chan_list, - params_legacy->nchan); + (params_legacy->nchan * sizeof(uint16))); + err = dhd_pno_set_legacy_pno(dhd, params_legacy->scan_fr, + params_legacy->pno_repeat, params_legacy->pno_freq_expo_max, + chan_list, params_legacy->nchan); if (err < 0) { DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", __FUNCTION__, err)); @@ -2570,7 +2400,6 @@ } exit: - kfree(pssid_list); return err; } @@ -2596,7 +2425,7 @@ } else { if (flush) { mutex_lock(&_pno_state->pno_mutex); - dhd_pno_reset_cfg_gscan(params, _pno_state, GSCAN_FLUSH_ALL_CFG); + dhd_pno_reset_cfg_gscan(dhd, params, _pno_state, GSCAN_FLUSH_ALL_CFG); mutex_unlock(&_pno_state->pno_mutex); } /* Need to stop all gscan */ @@ -2637,13 +2466,14 @@ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { if (old_flag != gscan_params->send_all_results_flag) { wl_pfn_gscan_cfg_t gscan_cfg; + gscan_cfg.version = WL_GSCAN_CFG_VERSION; gscan_cfg.flags = (gscan_params->send_all_results_flag & - GSCAN_SEND_ALL_RESULTS_MASK); + GSCAN_SEND_ALL_RESULTS_MASK); gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK; if ((err = _dhd_pno_gscan_cfg(dhd, &gscan_cfg, - sizeof(wl_pfn_gscan_cfg_t))) < 0) { + sizeof(wl_pfn_gscan_cfg_t))) < 0) { DHD_ERROR(("%s : pno_gscan_cfg failed (err %d) in firmware\n", __FUNCTION__, err)); goto exit_mutex_unlock; @@ -2661,7 +2491,7 @@ } /* Cleanup any consumed results - * Return TRUE if all results consumed, else FALSE + * Return TRUE if all results consumed else FALSE */ int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd) { @@ -2679,7 +2509,9 @@ while (iter) { if (iter->tot_consumed == iter->tot_count) { tmp = iter->next; - kfree(iter); + MFREE(dhd->osh, iter, + ((iter->tot_count - 1) * sizeof(wifi_gscan_result_t)) + + sizeof(gscan_results_cache_t)); iter = tmp; } else break; @@ -2696,14 +2528,29 @@ uint32 timestamp = 0, ts = 0, i, j, timediff; dhd_pno_params_t *params; dhd_pno_status_info_t *_pno_state; - wl_pfn_lnet_info_t *plnetinfo; + wl_pfn_lnet_info_v1_t *plnetinfo; + wl_pfn_lnet_info_v2_t *plnetinfo_v2; struct dhd_pno_gscan_params *gscan_params; - wl_pfn_lscanresults_t *plbestnet = NULL; + wl_pfn_lscanresults_v1_t *plbestnet_v1 = NULL; + wl_pfn_lscanresults_v2_t *plbestnet_v2 = NULL; gscan_results_cache_t *iter, *tail; wifi_gscan_result_t *result; uint8 *nAPs_per_scan = NULL; uint8 num_scans_in_cur_iter; uint16 count; + uint16 fwcount; + uint16 fwstatus = PFN_INCOMPLETE; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + struct timespec64 tm_spec; +#else + struct timespec tm_spec; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */ + + /* Static asserts in _dhd_pno_get_for_batch() below guarantee the v1 and v2 + * net_info and subnet_info structures are compatible in size and SSID offset, + * allowing v1 to be safely used in the code below except for lscanresults + * fields themselves (status, count, offset to netinfo). + */ NULL_CHECK(dhd, "dhd is NULL\n", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); @@ -2731,7 +2578,14 @@ goto exit; } - plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + plbestnet_v1 = (wl_pfn_lscanresults_v1_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + if (!plbestnet_v1) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", __FUNCTION__, + (int)PNO_BESTNET_LEN)); + err = BCME_NOMEM; + goto exit; + } + plbestnet_v2 = (wl_pfn_lscanresults_v2_t *)plbestnet_v1; mutex_lock(&_pno_state->pno_mutex); @@ -2746,136 +2600,284 @@ timediff = timediff >> 1; /* Ok, now lets start getting results from the FW */ - plbestnet->status = PFN_INCOMPLETE; tail = gscan_params->gscan_batch_cache; - while (plbestnet->status != PFN_COMPLETE) { - memset(plbestnet, 0, PNO_BESTNET_LEN); - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, - FALSE); + do { + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet_v1, PNO_BESTNET_LEN, + FALSE); if (err < 0) { DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n", __FUNCTION__, err)); goto exit_mutex_unlock; } - DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, - plbestnet->status, plbestnet->count)); - if (plbestnet->version != PFN_SCANRESULT_VERSION) { - err = BCME_VERSION; - DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", - plbestnet->version, PFN_SCANRESULT_VERSION)); - goto exit_mutex_unlock; - } - if (plbestnet->count == 0) { - DHD_PNO(("No more batch results\n")); - goto exit_mutex_unlock; - } - num_scans_in_cur_iter = 0; - timestamp = plbestnet->netinfo[0].timestamp; - /* find out how many scans' results did we get in this batch of FW results */ - for (i = 0, count = 0; i < plbestnet->count; i++, count++) { - plnetinfo = &plbestnet->netinfo[i]; - /* Unlikely to happen, but just in case the results from - * FW doesnt make sense..... Assume its part of one single scan - */ - if (num_scans_in_cur_iter > gscan_params->mscan) { - num_scans_in_cur_iter = 0; - count = plbestnet->count; - break; - } - if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { - nAPs_per_scan[num_scans_in_cur_iter] = count; - count = 0; - num_scans_in_cur_iter++; - } - timestamp = plnetinfo->timestamp; - } - nAPs_per_scan[num_scans_in_cur_iter] = count; - num_scans_in_cur_iter++; - DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); - plnetinfo = &plbestnet->netinfo[0]; + get_monotonic_boottime(&tm_spec); + if (plbestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) { + fwstatus = plbestnet_v1->status; + fwcount = plbestnet_v1->count; + plnetinfo = &plbestnet_v1->netinfo[0]; - for (i = 0; i < num_scans_in_cur_iter; i++) { - iter = (gscan_results_cache_t *) - kmalloc(((nAPs_per_scan[i] - 1) * sizeof(wifi_gscan_result_t)) + - sizeof(gscan_results_cache_t), GFP_KERNEL); - if (!iter) { - DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", - __FUNCTION__, gscan_params->mscan)); - err = BCME_NOMEM; + DHD_PNO(("ver %d, status : %d, count %d\n", + plbestnet_v1->version, fwstatus, fwcount)); + + if (fwcount == 0) { + DHD_PNO(("No more batch results\n")); goto exit_mutex_unlock; } - /* Need this check because the new set of results from FW - * maybe a continuation of previous sets' scan results + if (fwcount > BESTN_MAX) { + DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n", + __FUNCTION__, fwcount, (int)BESTN_MAX)); + /* Process only BESTN_MAX number of results per batch */ + fwcount = BESTN_MAX; + } + num_scans_in_cur_iter = 0; + + timestamp = plnetinfo->timestamp; + /* find out how many scans' results did we get in + * this batch of FW results */ - if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { - iter->scan_id = ++gscan_params->scan_id; - } else { - iter->scan_id = gscan_params->scan_id; - } - DHD_PNO(("scan_id %d tot_count %d\n", gscan_params->scan_id, - nAPs_per_scan[i])); - iter->tot_count = nAPs_per_scan[i]; - iter->tot_consumed = 0; - iter->flag = 0; - if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { - DHD_PNO(("This scan is aborted\n")); - iter->flag = (ENABLE << PNO_STATUS_ABORT); - } else if (gscan_params->reason) { - iter->flag = (ENABLE << gscan_params->reason); - } - - if (!tail) { - gscan_params->gscan_batch_cache = iter; - } else { - tail->next = iter; - } - tail = iter; - iter->next = NULL; - for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { - result = &iter->results[j]; - - result->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, - (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) plnetinfo->RSSI; - /* Info not available & not expected */ - result->beacon_period = 0; - result->capability = 0; - result->ie_length = 0; - result->rtt = (uint64) plnetinfo->rtt0; - result->rtt_sd = (uint64) plnetinfo->rtt1; - result->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); - ts = plnetinfo->timestamp; - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length %d\n", - __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + for (i = 0, count = 0; i < fwcount; i++, count++, plnetinfo++) { + /* Unlikely to happen, but just in case the results from + * FW doesnt make sense..... Assume its part of one single scan + */ + if (num_scans_in_cur_iter >= gscan_params->mscan) { + num_scans_in_cur_iter = 0; + count = fwcount; + break; } - memcpy(result->ssid, plnetinfo->pfnsubnet.SSID, - plnetinfo->pfnsubnet.SSID_len); - result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; - memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, - ETHER_ADDR_LEN); - - DHD_PNO(("\tSSID : ")); - DHD_PNO(("\n")); - DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - result->macaddr.octet[0], - result->macaddr.octet[1], - result->macaddr.octet[2], - result->macaddr.octet[3], - result->macaddr.octet[4], - result->macaddr.octet[5])); - DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", - plnetinfo->pfnsubnet.channel, - plnetinfo->RSSI, plnetinfo->timestamp)); - DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", - plnetinfo->rtt0, plnetinfo->rtt1)); - + if (TIME_DIFF_MS(timestamp, plnetinfo->timestamp) > timediff) { + nAPs_per_scan[num_scans_in_cur_iter] = count; + count = 0; + num_scans_in_cur_iter++; + } + timestamp = plnetinfo->timestamp; } + if (num_scans_in_cur_iter < gscan_params->mscan) { + nAPs_per_scan[num_scans_in_cur_iter] = count; + num_scans_in_cur_iter++; + } + + DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); + /* reset plnetinfo to the first item for the next loop */ + plnetinfo -= i; + + for (i = 0; i < num_scans_in_cur_iter; i++) { + iter = (gscan_results_cache_t *) + MALLOCZ(dhd->osh, ((nAPs_per_scan[i] - 1) * + sizeof(wifi_gscan_result_t)) + + sizeof(gscan_results_cache_t)); + if (!iter) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", + __FUNCTION__, gscan_params->mscan)); + err = BCME_NOMEM; + goto exit_mutex_unlock; + } + /* Need this check because the new set of results from FW + * maybe a continuation of previous sets' scan results + */ + if (TIME_DIFF_MS(ts, plnetinfo->timestamp) > timediff) { + iter->scan_id = ++gscan_params->scan_id; + } else { + iter->scan_id = gscan_params->scan_id; + } + DHD_PNO(("scan_id %d tot_count %d \n", + gscan_params->scan_id, nAPs_per_scan[i])); + iter->tot_count = nAPs_per_scan[i]; + iter->tot_consumed = 0; + iter->flag = 0; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + DHD_PNO(("This scan is aborted\n")); + iter->flag = (ENABLE << PNO_STATUS_ABORT); + } else if (gscan_params->reason) { + iter->flag = (ENABLE << gscan_params->reason); + } + + if (!tail) { + gscan_params->gscan_batch_cache = iter; + } else { + tail->next = iter; + } + tail = iter; + iter->next = NULL; + for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo++) { + result = &iter->results[j]; + + result->channel = + wf_channel2mhz(plnetinfo->pfnsubnet.channel, + (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) plnetinfo->RSSI; + result->beacon_period = 0; + result->capability = 0; + result->rtt = (uint64) plnetinfo->rtt0; + result->rtt_sd = (uint64) plnetinfo->rtt1; + result->ts = convert_fw_rel_time_to_systime(&tm_spec, + plnetinfo->timestamp); + ts = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d\n", + __FUNCTION__, + plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(result->ssid, plnetinfo->pfnsubnet.SSID, + plnetinfo->pfnsubnet.SSID_len); + result->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; + memcpy(&result->macaddr, &plnetinfo->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + + DHD_PNO(("\tSSID : ")); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: "MACDBG"\n", + MAC2STRDBG(result->macaddr.octet))); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", + plnetinfo->rtt0, plnetinfo->rtt1)); + + } + } + + } else if (plbestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) { + fwstatus = plbestnet_v2->status; + fwcount = plbestnet_v2->count; + plnetinfo_v2 = (wl_pfn_lnet_info_v2_t*)&plbestnet_v2->netinfo[0]; + + DHD_PNO(("ver %d, status : %d, count %d\n", + plbestnet_v2->version, fwstatus, fwcount)); + + if (fwcount == 0) { + DHD_PNO(("No more batch results\n")); + goto exit_mutex_unlock; + } + if (fwcount > BESTN_MAX) { + DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n", + __FUNCTION__, fwcount, (int)BESTN_MAX)); + /* Process only BESTN_MAX number of results per batch */ + fwcount = BESTN_MAX; + } + num_scans_in_cur_iter = 0; + + timestamp = plnetinfo_v2->timestamp; + /* find out how many scans' results did we get + * in this batch of FW results + */ + for (i = 0, count = 0; i < fwcount; i++, count++, plnetinfo_v2++) { + /* Unlikely to happen, but just in case the results from + * FW doesnt make sense..... Assume its part of one single scan + */ + if (num_scans_in_cur_iter >= gscan_params->mscan) { + num_scans_in_cur_iter = 0; + count = fwcount; + break; + } + if (TIME_DIFF_MS(timestamp, plnetinfo_v2->timestamp) > timediff) { + nAPs_per_scan[num_scans_in_cur_iter] = count; + count = 0; + num_scans_in_cur_iter++; + } + timestamp = plnetinfo_v2->timestamp; + } + if (num_scans_in_cur_iter < gscan_params->mscan) { + nAPs_per_scan[num_scans_in_cur_iter] = count; + num_scans_in_cur_iter++; + } + + DHD_PNO(("num_scans_in_cur_iter %d\n", num_scans_in_cur_iter)); + /* reset plnetinfo to the first item for the next loop */ + plnetinfo_v2 -= i; + + for (i = 0; i < num_scans_in_cur_iter; i++) { + iter = (gscan_results_cache_t *) + MALLOCZ(dhd->osh, ((nAPs_per_scan[i] - 1) * + sizeof(wifi_gscan_result_t)) + + sizeof(gscan_results_cache_t)); + if (!iter) { + DHD_ERROR(("%s :Out of memory!! Cant malloc %d bytes\n", + __FUNCTION__, gscan_params->mscan)); + err = BCME_NOMEM; + goto exit_mutex_unlock; + } + /* Need this check because the new set of results from FW + * maybe a continuation of previous sets' scan results + */ + if (TIME_DIFF_MS(ts, plnetinfo_v2->timestamp) > timediff) { + iter->scan_id = ++gscan_params->scan_id; + } else { + iter->scan_id = gscan_params->scan_id; + } + DHD_PNO(("scan_id %d tot_count %d ch_bucket %x\n", + gscan_params->scan_id, nAPs_per_scan[i], + plbestnet_v2->scan_ch_buckets[i])); + iter->tot_count = nAPs_per_scan[i]; + iter->scan_ch_bucket = plbestnet_v2->scan_ch_buckets[i]; + iter->tot_consumed = 0; + iter->flag = 0; + if (plnetinfo_v2->flags & PFN_PARTIAL_SCAN_MASK) { + DHD_PNO(("This scan is aborted\n")); + iter->flag = (ENABLE << PNO_STATUS_ABORT); + } else if (gscan_params->reason) { + iter->flag = (ENABLE << gscan_params->reason); + } + + if (!tail) { + gscan_params->gscan_batch_cache = iter; + } else { + tail->next = iter; + } + tail = iter; + iter->next = NULL; + for (j = 0; j < nAPs_per_scan[i]; j++, plnetinfo_v2++) { + result = &iter->results[j]; + + result->channel = + wf_channel2mhz(plnetinfo_v2->pfnsubnet.channel, + (plnetinfo_v2->pfnsubnet.channel <= + CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + result->rssi = (int32) plnetinfo_v2->RSSI; + /* Info not available & not expected */ + result->beacon_period = 0; + result->capability = 0; + result->rtt = (uint64) plnetinfo_v2->rtt0; + result->rtt_sd = (uint64) plnetinfo_v2->rtt1; + result->ts = convert_fw_rel_time_to_systime(&tm_spec, + plnetinfo_v2->timestamp); + ts = plnetinfo_v2->timestamp; + if (plnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d\n", + __FUNCTION__, + plnetinfo_v2->pfnsubnet.SSID_len)); + plnetinfo_v2->pfnsubnet.SSID_len = + DOT11_MAX_SSID_LEN; + } + memcpy(result->ssid, plnetinfo_v2->pfnsubnet.u.SSID, + plnetinfo_v2->pfnsubnet.SSID_len); + result->ssid[plnetinfo_v2->pfnsubnet.SSID_len] = '\0'; + memcpy(&result->macaddr, &plnetinfo_v2->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + + DHD_PNO(("\tSSID : ")); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: "MACDBG"\n", + MAC2STRDBG(result->macaddr.octet))); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo_v2->pfnsubnet.channel, + plnetinfo_v2->RSSI, plnetinfo_v2->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", + plnetinfo_v2->rtt0, plnetinfo_v2->rtt1)); + + } + } + + } else { + err = BCME_VERSION; + DHD_ERROR(("bestnet fw version %d not supported\n", + plbestnet_v1->version)); + goto exit_mutex_unlock; } - } + } while (fwstatus == PFN_INCOMPLETE); + exit_mutex_unlock: mutex_unlock(&_pno_state->pno_mutex); exit: @@ -2883,15 +2885,175 @@ smp_wmb(); wake_up_interruptible(&_pno_state->batch_get_wait); if (nAPs_per_scan) { - MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan); + MFREE(dhd->osh, nAPs_per_scan, gscan_params->mscan * sizeof(uint8)); } - if (plbestnet) { - MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + if (plbestnet_v1) { + MFREE(dhd->osh, plbestnet_v1, PNO_BESTNET_LEN); } DHD_PNO(("Batch retrieval done!\n")); return err; } #endif /* GSCAN_SUPPORT */ + +#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) +static void * +dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len) +{ + gscan_results_cache_t *iter, *results; + dhd_pno_status_info_t *_pno_state; + dhd_pno_params_t *_params; + uint16 num_scan_ids = 0, num_results = 0; + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + iter = results = _params->params_gscan.gscan_batch_cache; + while (iter) { + num_results += iter->tot_count - iter->tot_consumed; + num_scan_ids++; + iter = iter->next; + } + + *len = ((num_results << 16) | (num_scan_ids)); + return results; +} + +void * +dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, + void *info, uint32 *len) +{ + void *ret = NULL; + dhd_pno_gscan_capabilities_t *ptr; + dhd_pno_ssid_t *ssid_elem; + dhd_pno_params_t *_params; + dhd_epno_ssid_cfg_t *epno_cfg; + dhd_pno_status_info_t *_pno_state; + + if (!dhd || !dhd->pno_state) { + DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__)); + return NULL; + } + + _pno_state = PNO_GET_PNOSTATE(dhd); + _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; + + if (!len) { + DHD_ERROR(("%s: len is NULL\n", __FUNCTION__)); + return NULL; + } + + switch (type) { + case DHD_PNO_GET_CAPABILITIES: + ptr = (dhd_pno_gscan_capabilities_t *) + MALLOCZ(dhd->osh, sizeof(dhd_pno_gscan_capabilities_t)); + if (!ptr) + break; + /* Hardcoding these values for now, need to get + * these values from FW, will change in a later check-in + */ + ptr->max_scan_cache_size = GSCAN_MAX_AP_CACHE; + ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS; + ptr->max_ap_cache_per_scan = GSCAN_MAX_AP_CACHE_PER_SCAN; + ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX; + ptr->max_scan_reporting_threshold = 100; + ptr->max_hotlist_bssids = PFN_HOTLIST_MAX_NUM_APS; + ptr->max_hotlist_ssids = 0; + ptr->max_significant_wifi_change_aps = 0; + ptr->max_bssid_history_entries = 0; + ptr->max_epno_ssid_crc32 = MAX_EPNO_SSID_NUM; + ptr->max_epno_hidden_ssid = MAX_EPNO_HIDDEN_SSID; + ptr->max_white_list_ssid = MAX_WHITELIST_SSID; + ret = (void *)ptr; + *len = sizeof(dhd_pno_gscan_capabilities_t); + break; + + case DHD_PNO_GET_BATCH_RESULTS: + ret = dhd_get_gscan_batch_results(dhd, len); + break; + case DHD_PNO_GET_CHANNEL_LIST: + if (info) { + uint16 ch_list[WL_NUMCHANNELS]; + uint32 *p, mem_needed, i; + int32 err, nchan = WL_NUMCHANNELS; + uint32 *gscan_band = (uint32 *) info; + uint8 band = 0; + + /* No band specified?, nothing to do */ + if ((*gscan_band & GSCAN_BAND_MASK) == 0) { + DHD_PNO(("No band specified\n")); + *len = 0; + break; + } + + /* HAL and DHD use different bits for 2.4G and + * 5G in bitmap. Hence translating it here... + */ + if (*gscan_band & GSCAN_BG_BAND_MASK) { + band |= WLC_BAND_2G; + } + if (*gscan_band & GSCAN_A_BAND_MASK) { + band |= WLC_BAND_5G; + } + + err = _dhd_pno_get_channels(dhd, ch_list, &nchan, + (band & GSCAN_ABG_BAND_MASK), + !(*gscan_band & GSCAN_DFS_MASK)); + + if (err < 0) { + DHD_ERROR(("%s: failed to get valid channel list\n", + __FUNCTION__)); + *len = 0; + } else { + mem_needed = sizeof(uint32) * nchan; + p = (uint32 *)MALLOC(dhd->osh, mem_needed); + if (!p) { + DHD_ERROR(("%s: Unable to malloc %d bytes\n", + __FUNCTION__, mem_needed)); + break; + } + for (i = 0; i < nchan; i++) { + p[i] = wf_channel2mhz(ch_list[i], + (ch_list[i] <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + } + ret = p; + *len = mem_needed; + } + } else { + *len = 0; + DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__)); + } + break; + case DHD_PNO_GET_NEW_EPNO_SSID_ELEM: + epno_cfg = &_params->params_gscan.epno_cfg; + if (epno_cfg->num_epno_ssid >= + MAX_EPNO_SSID_NUM) { + DHD_ERROR(("Excessive number of ePNO SSIDs programmed %d\n", + epno_cfg->num_epno_ssid)); + return NULL; + } + if (!epno_cfg->num_epno_ssid) { + INIT_LIST_HEAD(&epno_cfg->epno_ssid_list); + } + ssid_elem = MALLOCZ(dhd->osh, sizeof(dhd_pno_ssid_t)); + if (!ssid_elem) { + DHD_ERROR(("EPNO ssid: cannot alloc %zd bytes", + sizeof(dhd_pno_ssid_t))); + return NULL; + } + epno_cfg->num_epno_ssid++; + list_add_tail(&ssid_elem->list, &epno_cfg->epno_ssid_list); + ret = ssid_elem; + break; + default: + DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type)); + break; + } + + return ret; + +} +#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ static int _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) @@ -2901,20 +3063,38 @@ uint32 timestamp = 0; dhd_pno_params_t *_params = NULL; dhd_pno_status_info_t *_pno_state = NULL; - wl_pfn_lscanresults_t *plbestnet = NULL; - wl_pfn_lnet_info_t *plnetinfo; + wl_pfn_lscanresults_v1_t *plbestnet_v1 = NULL; + wl_pfn_lscanresults_v2_t *plbestnet_v2 = NULL; + wl_pfn_lnet_info_v1_t *plnetinfo; + wl_pfn_lnet_info_v2_t *plnetinfo_v2; dhd_pno_bestnet_entry_t *pbestnet_entry; dhd_pno_best_header_t *pbestnetheader = NULL; dhd_pno_scan_results_t *pscan_results = NULL, *siter, *snext; bool allocate_header = FALSE; + uint16 fwstatus = PFN_INCOMPLETE; + uint16 fwcount; + NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + + /* The static asserts below guarantee the v1 and v2 net_info and subnet_info + * structures are compatible in size and SSID offset, allowing v1 to be safely + * used in the code below except for lscanresults fields themselves + * (status, count, offset to netinfo). + */ + STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t)); + STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t)); + STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t)); + STATIC_ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) == + OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID)); + + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + if (!dhd_support_sta_mode(dhd)) { err = BCME_BADOPTION; goto exit_no_unlock; } - DHD_PNO(("%s enter\n", __FUNCTION__)); - _pno_state = PNO_GET_PNOSTATE(dhd); if (!WLS_SUPPORTED(_pno_state)) { DHD_ERROR(("%s : wifi location service is not supported\n", __FUNCTION__)); @@ -2939,8 +3119,10 @@ /* this is a first try to get batching results */ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { /* move the scan_results_list to expired_scan_results_lists */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(siter, snext, &_params->params_batch.get_batch.scan_results_list, list) { + GCC_DIAGNOSTIC_POP(); list_move_tail(&siter->list, &_params->params_batch.get_batch.expired_scan_results_list); } @@ -2975,14 +3157,15 @@ list_add(&pscan_results->list, &_params->params_batch.get_batch.scan_results_list); } - plbestnet = (wl_pfn_lscanresults_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); - NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err); + + plbestnet_v1 = (wl_pfn_lscanresults_v1_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN); + NULL_CHECK(plbestnet_v1, "failed to allocate buffer for bestnet", err); + plbestnet_v2 = (wl_pfn_lscanresults_v2_t*)plbestnet_v1; + DHD_PNO(("%s enter\n", __FUNCTION__)); - memset(plbestnet, 0, PNO_BESTNET_LEN); - while (plbestnet->status != PFN_COMPLETE) { - memset(plbestnet, 0, PNO_BESTNET_LEN); - err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet, PNO_BESTNET_LEN, - FALSE); + do { + err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, (char *)plbestnet_v1, PNO_BESTNET_LEN, + FALSE); if (err < 0) { if (err == BCME_EPERM) { DHD_ERROR(("we cannot get the batching data " @@ -2995,107 +3178,229 @@ goto exit; } } - DHD_PNO(("ver %d, status : %d, count %d\n", plbestnet->version, - plbestnet->status, plbestnet->count)); - if (plbestnet->version != PFN_SCANRESULT_VERSION) { - err = BCME_VERSION; - DHD_ERROR(("bestnet version(%d) is mismatch with Driver version(%d)\n", - plbestnet->version, PFN_SCANRESULT_VERSION)); - goto exit; - } - plnetinfo = plbestnet->netinfo; - for (i = 0; i < plbestnet->count; i++) { - pbestnet_entry = (dhd_pno_bestnet_entry_t *) - MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); - if (pbestnet_entry == NULL) { - err = BCME_NOMEM; - DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + + if (plbestnet_v1->version == PFN_LBEST_SCAN_RESULT_VERSION_V1) { + fwstatus = plbestnet_v1->status; + fwcount = plbestnet_v1->count; + plnetinfo = &plbestnet_v1->netinfo[0]; + if (fwcount == 0) { + DHD_PNO(("No more batch results\n")); goto exit; } - memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); - pbestnet_entry->recorded_time = jiffies; /* record the current time */ - /* create header for the first entry */ - allocate_header = (i == 0)? TRUE : FALSE; - /* check whether the new generation is started or not */ - if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) - > TIME_MIN_DIFF)) - allocate_header = TRUE; - timestamp = plnetinfo->timestamp; - if (allocate_header) { - pbestnetheader = (dhd_pno_best_header_t *) - MALLOC(dhd->osh, BEST_HEADER_SIZE); - if (pbestnetheader == NULL) { + if (fwcount > BESTN_MAX) { + DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n", + __FUNCTION__, fwcount, (int)BESTN_MAX)); + /* Process only BESTN_MAX number of results per batch */ + fwcount = BESTN_MAX; + } + for (i = 0; i < fwcount; i++) { + pbestnet_entry = (dhd_pno_bestnet_entry_t *) + MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); + if (pbestnet_entry == NULL) { err = BCME_NOMEM; - if (pbestnet_entry) - MFREE(dhd->osh, pbestnet_entry, - BESTNET_ENTRY_SIZE); DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); goto exit; } - /* increase total cnt of bestnet header */ - pscan_results->cnt_header++; - /* need to record the reason to call dhd_pno_get_for_bach */ - if (reason) - pbestnetheader->reason = (ENABLE << reason); - memset(pbestnetheader, 0, BEST_HEADER_SIZE); - /* initialize the head of linked list */ - INIT_LIST_HEAD(&(pbestnetheader->entry_list)); - /* link the pbestnet heaer into existed list */ - if (pscan_results->bestnetheader == NULL) - /* In case of header */ - pscan_results->bestnetheader = pbestnetheader; - else { - dhd_pno_best_header_t *head = pscan_results->bestnetheader; - pscan_results->bestnetheader = pbestnetheader; - pbestnetheader->next = head; + memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); + /* record the current time */ + pbestnet_entry->recorded_time = jiffies; + /* create header for the first entry */ + allocate_header = (i == 0)? TRUE : FALSE; + /* check whether the new generation is started or not */ + if (timestamp && (TIME_DIFF(timestamp, plnetinfo->timestamp) + > TIME_MIN_DIFF)) + allocate_header = TRUE; + timestamp = plnetinfo->timestamp; + if (allocate_header) { + pbestnetheader = (dhd_pno_best_header_t *) + MALLOC(dhd->osh, BEST_HEADER_SIZE); + if (pbestnetheader == NULL) { + err = BCME_NOMEM; + if (pbestnet_entry) + MFREE(dhd->osh, pbestnet_entry, + BESTNET_ENTRY_SIZE); + DHD_ERROR(("failed to allocate" + " dhd_pno_bestnet_entry\n")); + goto exit; + } + /* increase total cnt of bestnet header */ + pscan_results->cnt_header++; + /* need to record the reason to call dhd_pno_get_for_bach */ + if (reason) + pbestnetheader->reason = (ENABLE << reason); + memset(pbestnetheader, 0, BEST_HEADER_SIZE); + /* initialize the head of linked list */ + INIT_LIST_HEAD(&(pbestnetheader->entry_list)); + /* link the pbestnet heaer into existed list */ + if (pscan_results->bestnetheader == NULL) + /* In case of header */ + pscan_results->bestnetheader = pbestnetheader; + else { + dhd_pno_best_header_t *head = + pscan_results->bestnetheader; + pscan_results->bestnetheader = pbestnetheader; + pbestnetheader->next = head; + } } + pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; + pbestnet_entry->RSSI = plnetinfo->RSSI; + if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { + /* if RSSI is positive value, we assume that + * this scan is aborted by other scan + */ + DHD_PNO(("This scan is aborted\n")); + pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); + } + pbestnet_entry->rtt0 = plnetinfo->rtt0; + pbestnet_entry->rtt1 = plnetinfo->rtt1; + pbestnet_entry->timestamp = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length" + " %d: trimming it to max\n", + __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; + memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, + pbestnet_entry->SSID_len); + memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + /* add the element into list */ + list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); + /* increase best entry count */ + pbestnetheader->tot_cnt++; + pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; + DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); + DHD_PNO(("\tSSID : ")); + for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) + DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: "MACDBG"\n", + MAC2STRDBG(plnetinfo->pfnsubnet.BSSID.octet))); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo->pfnsubnet.channel, + plnetinfo->RSSI, plnetinfo->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, + plnetinfo->rtt1)); + plnetinfo++; } - /* fills the best network info */ - pbestnet_entry->channel = plnetinfo->pfnsubnet.channel; - pbestnet_entry->RSSI = plnetinfo->RSSI; - if (plnetinfo->flags & PFN_PARTIAL_SCAN_MASK) { - /* if RSSI is positive value, we assume that - * this scan is aborted by other scan - */ - DHD_PNO(("This scan is aborted\n")); - pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); + } else if (plbestnet_v2->version == PFN_LBEST_SCAN_RESULT_VERSION_V2) { + fwstatus = plbestnet_v2->status; + fwcount = plbestnet_v2->count; + plnetinfo_v2 = (wl_pfn_lnet_info_v2_t*)&plbestnet_v2->netinfo[0]; + if (fwcount == 0) { + DHD_PNO(("No more batch results\n")); + goto exit; } - pbestnet_entry->rtt0 = plnetinfo->rtt0; - pbestnet_entry->rtt1 = plnetinfo->rtt1; - pbestnet_entry->timestamp = plnetinfo->timestamp; - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", - __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + if (fwcount > BESTN_MAX) { + DHD_ERROR(("%s :fwcount %d is greater than BESTN_MAX %d \n", + __FUNCTION__, fwcount, (int)BESTN_MAX)); + /* Process only BESTN_MAX number of results per batch */ + fwcount = BESTN_MAX; } - pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; - memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, - pbestnet_entry->SSID_len); - memcpy(&pbestnet_entry->BSSID, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); - /* add the element into list */ - list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); - /* increase best entry count */ - pbestnetheader->tot_cnt++; - pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; - DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); - DHD_PNO(("\tSSID : ")); - for (j = 0; j < plnetinfo->pfnsubnet.SSID_len; j++) - DHD_PNO(("%c", plnetinfo->pfnsubnet.SSID[j])); - DHD_PNO(("\n")); - DHD_PNO(("\tBSSID: %02x:%02x:%02x:%02x:%02x:%02x\n", - plnetinfo->pfnsubnet.BSSID.octet[0], - plnetinfo->pfnsubnet.BSSID.octet[1], - plnetinfo->pfnsubnet.BSSID.octet[2], - plnetinfo->pfnsubnet.BSSID.octet[3], - plnetinfo->pfnsubnet.BSSID.octet[4], - plnetinfo->pfnsubnet.BSSID.octet[5])); - DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", - plnetinfo->pfnsubnet.channel, - plnetinfo->RSSI, plnetinfo->timestamp)); - DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo->rtt0, plnetinfo->rtt1)); - plnetinfo++; + DHD_PNO(("ver %d, status : %d, count %d\n", + plbestnet_v2->version, fwstatus, fwcount)); + + for (i = 0; i < fwcount; i++) { + pbestnet_entry = (dhd_pno_bestnet_entry_t *) + MALLOC(dhd->osh, BESTNET_ENTRY_SIZE); + if (pbestnet_entry == NULL) { + err = BCME_NOMEM; + DHD_ERROR(("failed to allocate dhd_pno_bestnet_entry\n")); + goto exit; + } + memset(pbestnet_entry, 0, BESTNET_ENTRY_SIZE); + /* record the current time */ + pbestnet_entry->recorded_time = jiffies; + /* create header for the first entry */ + allocate_header = (i == 0)? TRUE : FALSE; + /* check whether the new generation is started or not */ + if (timestamp && (TIME_DIFF(timestamp, plnetinfo_v2->timestamp) + > TIME_MIN_DIFF)) + allocate_header = TRUE; + timestamp = plnetinfo_v2->timestamp; + if (allocate_header) { + pbestnetheader = (dhd_pno_best_header_t *) + MALLOC(dhd->osh, BEST_HEADER_SIZE); + if (pbestnetheader == NULL) { + err = BCME_NOMEM; + if (pbestnet_entry) + MFREE(dhd->osh, pbestnet_entry, + BESTNET_ENTRY_SIZE); + DHD_ERROR(("failed to allocate" + " dhd_pno_bestnet_entry\n")); + goto exit; + } + /* increase total cnt of bestnet header */ + pscan_results->cnt_header++; + /* need to record the reason to call dhd_pno_get_for_bach */ + if (reason) + pbestnetheader->reason = (ENABLE << reason); + memset(pbestnetheader, 0, BEST_HEADER_SIZE); + /* initialize the head of linked list */ + INIT_LIST_HEAD(&(pbestnetheader->entry_list)); + /* link the pbestnet heaer into existed list */ + if (pscan_results->bestnetheader == NULL) + /* In case of header */ + pscan_results->bestnetheader = pbestnetheader; + else { + dhd_pno_best_header_t *head = + pscan_results->bestnetheader; + pscan_results->bestnetheader = pbestnetheader; + pbestnetheader->next = head; + } + } + /* fills the best network info */ + pbestnet_entry->channel = plnetinfo_v2->pfnsubnet.channel; + pbestnet_entry->RSSI = plnetinfo_v2->RSSI; + if (plnetinfo_v2->flags & PFN_PARTIAL_SCAN_MASK) { + /* if RSSI is positive value, we assume that + * this scan is aborted by other scan + */ + DHD_PNO(("This scan is aborted\n")); + pbestnetheader->reason = (ENABLE << PNO_STATUS_ABORT); + } + pbestnet_entry->rtt0 = plnetinfo_v2->rtt0; + pbestnet_entry->rtt1 = plnetinfo_v2->rtt1; + pbestnet_entry->timestamp = plnetinfo_v2->timestamp; + if (plnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length" + " %d: trimming it to max\n", + __FUNCTION__, plnetinfo_v2->pfnsubnet.SSID_len)); + plnetinfo_v2->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + pbestnet_entry->SSID_len = plnetinfo_v2->pfnsubnet.SSID_len; + memcpy(pbestnet_entry->SSID, plnetinfo_v2->pfnsubnet.u.SSID, + pbestnet_entry->SSID_len); + memcpy(&pbestnet_entry->BSSID, &plnetinfo_v2->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + /* add the element into list */ + list_add_tail(&pbestnet_entry->list, &pbestnetheader->entry_list); + /* increase best entry count */ + pbestnetheader->tot_cnt++; + pbestnetheader->tot_size += BESTNET_ENTRY_SIZE; + DHD_PNO(("Header %d\n", pscan_results->cnt_header - 1)); + DHD_PNO(("\tSSID : ")); + for (j = 0; j < plnetinfo_v2->pfnsubnet.SSID_len; j++) + DHD_PNO(("%c", plnetinfo_v2->pfnsubnet.u.SSID[j])); + DHD_PNO(("\n")); + DHD_PNO(("\tBSSID: "MACDBG"\n", + MAC2STRDBG(plnetinfo_v2->pfnsubnet.BSSID.octet))); + DHD_PNO(("\tchannel: %d, RSSI: %d, timestamp: %d ms\n", + plnetinfo_v2->pfnsubnet.channel, + plnetinfo_v2->RSSI, plnetinfo_v2->timestamp)); + DHD_PNO(("\tRTT0 : %d, RTT1: %d\n", plnetinfo_v2->rtt0, + plnetinfo_v2->rtt1)); + plnetinfo_v2++; + } + } else { + err = BCME_VERSION; + DHD_ERROR(("bestnet fw version %d not supported\n", + plbestnet_v1->version)); + goto exit; } - } + } while (fwstatus != PFN_COMPLETE); + if (pscan_results->cnt_header == 0) { /* In case that we didn't get any data from the firmware * Remove the current scan_result list from get_bach.scan_results_list. @@ -3104,16 +3409,19 @@ list_del(&pscan_results->list); MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); _params->params_batch.get_batch.top_node_cnt--; + } else { + /* increase total scan count using current scan count */ + _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; } - /* increase total scan count using current scan count */ - _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; if (buf && bufsize) { /* This is a first try to get batching results */ if (!list_empty(&_params->params_batch.get_batch.scan_results_list)) { /* move the scan_results_list to expired_scan_results_lists */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(siter, snext, &_params->params_batch.get_batch.scan_results_list, list) { + GCC_DIAGNOSTIC_POP(); list_move_tail(&siter->list, &_params->params_batch.get_batch.expired_scan_results_list); } @@ -3131,8 +3439,8 @@ } } exit: - if (plbestnet) - MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); + if (plbestnet_v1) + MFREE(dhd->osh, plbestnet_v1, PNO_BESTNET_LEN); if (_params) { _params->params_batch.get_batch.buf = NULL; _params->params_batch.get_batch.bufsize = 0; @@ -3140,7 +3448,11 @@ } mutex_unlock(&_pno_state->pno_mutex); exit_no_unlock: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + if (swait_active(&_pno_state->get_batch_done.wait)) +#else if (waitqueue_active(&_pno_state->get_batch_done.wait)) +#endif/* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */ complete(&_pno_state->get_batch_done); return err; } @@ -3151,12 +3463,16 @@ dhd_pub_t *dhd; struct dhd_pno_batch_params *params_batch; DHD_PNO(("%s enter\n", __FUNCTION__)); + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); _pno_state = container_of(work, struct dhd_pno_status_info, work); + GCC_DIAGNOSTIC_POP(); + dhd = _pno_state->dhd; if (dhd == NULL) { DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); return; } + #ifdef GSCAN_SUPPORT _dhd_pno_get_gscan_batch_from_fw(dhd); #endif /* GSCAN_SUPPORT */ @@ -3202,13 +3518,13 @@ msecs_to_jiffies(GSCAN_BATCH_GET_MAX_WAIT)); } } else -#endif +#endif // endif { if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__)); memset(pbuf, 0, bufsize); - pbuf += sprintf(pbuf, "scancount=%d\n", 0); - sprintf(pbuf, "%s", RESULTS_END_MARKER); + pbuf += snprintf(pbuf, bufsize, "scancount=%d\n", 0); + snprintf(pbuf, bufsize, "%s", RESULTS_END_MARKER); err = strlen(buf); goto exit; } @@ -3222,7 +3538,7 @@ #ifdef GSCAN_SUPPORT if (!(_pno_state->pno_mode & DHD_PNO_GSCAN_MODE)) -#endif +#endif // endif err = params_batch->get_batch.bytes_written; exit: return err; @@ -3237,7 +3553,6 @@ dhd_pno_status_info_t *_pno_state; dhd_pno_params_t *_params; wl_pfn_bssid_t *p_pfn_bssid = NULL; - wlc_ssid_ext_t *p_ssid_list = NULL; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); _pno_state = PNO_GET_PNOSTATE(dhd); @@ -3258,7 +3573,7 @@ DHD_PNO(("Gscan is ongoing, nothing to stop here\n")); return err; } -#endif +#endif // endif if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) { DHD_ERROR(("%s : PNO BATCH MODE is not enabled\n", __FUNCTION__)); @@ -3267,23 +3582,23 @@ _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { mode = _pno_state->pno_mode; - dhd_pno_clean(dhd); + err = dhd_pno_clean(dhd); + if (err < 0) { + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", + __FUNCTION__, err)); + goto exit; + } + _pno_state->pno_mode = mode; /* restart Legacy PNO if the Legacy PNO is on */ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { struct dhd_pno_legacy_params *_params_legacy; _params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, - _params_legacy->scan_fr, _params_legacy->pno_repeat, - _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, - _params_legacy->nchan); + err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr, + _params_legacy->pno_repeat, + _params_legacy->pno_freq_expo_max, + _params_legacy->chan_list, _params_legacy->nchan); if (err < 0) { DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", __FUNCTION__, err)); @@ -3292,8 +3607,8 @@ } else if (_pno_state->pno_mode & DHD_PNO_HOTLIST_MODE) { struct dhd_pno_bssid *iter, *next; _params = &(_pno_state->pno_params_arr[INDEX_OF_HOTLIST_PARAMS]); - p_pfn_bssid = kzalloc(sizeof(wl_pfn_bssid_t) * - _params->params_hotlist.nbssid, GFP_KERNEL); + p_pfn_bssid = (wl_pfn_bssid_t *)MALLOCZ(dhd->osh, + sizeof(wl_pfn_bssid_t) * _params->params_hotlist.nbssid); if (p_pfn_bssid == NULL) { DHD_ERROR(("%s : failed to allocate wl_pfn_bssid_t array" " (count: %d)", @@ -3304,8 +3619,10 @@ } i = 0; /* convert dhd_pno_bssid to wl_pfn_bssid */ + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); list_for_each_entry_safe(iter, next, &_params->params_hotlist.bssid_list, list) { + GCC_DIAGNOSTIC_POP(); memcpy(&p_pfn_bssid[i].macaddr, &iter->macaddr, ETHER_ADDR_LEN); p_pfn_bssid[i].flags = iter->flags; i++; @@ -3329,8 +3646,8 @@ exit: _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - kfree(p_ssid_list); - kfree(p_pfn_bssid); + MFREE(dhd->osh, p_pfn_bssid, + sizeof(wl_pfn_bssid_t) * _params->params_hotlist.nbssid); return err; } @@ -3407,7 +3724,7 @@ } DHD_PNO(("\n")); } -#endif +#endif // endif if (_params->params_hotlist.nchan) { /* copy the channel list into local array */ memcpy(_chan_list, _params->params_hotlist.chan_list, @@ -3465,7 +3782,8 @@ } } for (i = 0; i < hotlist_params->nbssid; i++) { - _pno_bssid = kzalloc(sizeof(struct dhd_pno_bssid), GFP_KERNEL); + _pno_bssid = (struct dhd_pno_bssid *)MALLOCZ(dhd->osh, + sizeof(struct dhd_pno_bssid)); NULL_CHECK(_pno_bssid, "_pfn_bssid is NULL", err); memcpy(&_pno_bssid->macaddr, &p_pfn_bssid[i].macaddr, ETHER_ADDR_LEN); _pno_bssid->flags = p_pfn_bssid[i].flags; @@ -3490,7 +3808,6 @@ uint32 mode = 0; dhd_pno_status_info_t *_pno_state; dhd_pno_params_t *_params; - wlc_ssid_ext_t *p_ssid_list = NULL; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); _pno_state = PNO_GET_PNOSTATE(dhd); @@ -3527,16 +3844,9 @@ struct dhd_pno_legacy_params *_params_legacy; _params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); - if (!p_ssid_list) { - err = BCME_NOMEM; - DHD_ERROR(("failed to get Legacy PNO SSID list\n")); - goto exit; - } - err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, - _params_legacy->scan_fr, _params_legacy->pno_repeat, - _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, - _params_legacy->nchan); + err = dhd_pno_set_legacy_pno(dhd, _params_legacy->scan_fr, + _params_legacy->pno_repeat, _params_legacy->pno_freq_expo_max, + _params_legacy->chan_list, _params_legacy->nchan); if (err < 0) { DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n", __FUNCTION__, err)); @@ -3563,7 +3873,6 @@ } } exit: - kfree(p_ssid_list); return err; } @@ -3599,82 +3908,6 @@ return err; } -/* Handle Significant WiFi Change (SWC) event from FW - * Send event to HAL when all results arrive from FW - */ -void * -dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes) -{ - void *ptr = NULL; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); - struct dhd_pno_gscan_params *gscan_params; - struct dhd_pno_swc_evt_param *params; - wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data; - wl_pfn_significant_net_t *change_array; - int i; - - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - params = &(gscan_params->param_significant); - - if (!results->total_count) { - *send_evt_bytes = 0; - return ptr; - } - - if (!params->results_rxed_so_far) { - if (!params->change_array) { - params->change_array = (wl_pfn_significant_net_t *) - kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count, - GFP_KERNEL); - - if (!params->change_array) { - DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__, - sizeof(wl_pfn_significant_net_t) * results->total_count)); - *send_evt_bytes = 0; - return ptr; - } - } else { - DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!")); - *send_evt_bytes = 0; - return ptr; - } - - } - - DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__, - results->pkt_count, results->total_count)); - - for (i = 0; i < results->pkt_count; i++) { - DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n", - results->list[i].BSSID.octet[0], - results->list[i].BSSID.octet[1], - results->list[i].BSSID.octet[2], - results->list[i].BSSID.octet[3], - results->list[i].BSSID.octet[4], - results->list[i].BSSID.octet[5])); - } - - change_array = ¶ms->change_array[params->results_rxed_so_far]; - memcpy(change_array, results->list, sizeof(wl_pfn_significant_net_t) * results->pkt_count); - params->results_rxed_so_far += results->pkt_count; - - if (params->results_rxed_so_far == results->total_count) { - params->results_rxed_so_far = 0; - *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count; - /* Pack up change buffer to send up and reset - * results_rxed_so_far, after its done. - */ - ptr = (void *) params->change_array; - /* expecting the callee to free this mem chunk */ - params->change_array = NULL; - } - else { - *send_evt_bytes = 0; - } - - return ptr; -} - void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type) { @@ -3697,7 +3930,9 @@ while (iter) { tmp = iter->next; - kfree(iter); + MFREE(dhd->osh, iter, + ((iter->tot_count - 1) * sizeof(wifi_gscan_result_t)) + + sizeof(gscan_results_cache_t)); iter = tmp; } @@ -3709,40 +3944,40 @@ { wl_bss_info_t *bi = NULL; wl_gscan_result_t *gscan_result; - wifi_gscan_result_t *result = NULL; + wifi_gscan_full_result_t *result = NULL; u32 bi_length = 0; uint8 channel; uint32 mem_needed; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + struct timespec64 ts; +#else struct timespec ts; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */ u32 bi_ie_length = 0; u32 bi_ie_offset = 0; *size = 0; - + GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); gscan_result = (wl_gscan_result_t *)data; - + GCC_DIAGNOSTIC_POP(); if (!gscan_result) { DHD_ERROR(("Invalid gscan result (NULL pointer)\n")); goto exit; } - if (!gscan_result->bss_info) { - DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n")); - goto exit; - } if ((len < sizeof(*gscan_result)) || - (len < dtoh32(gscan_result->buflen)) || - (dtoh32(gscan_result->buflen) > - (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { + (len < dtoh32(gscan_result->buflen)) || + (dtoh32(gscan_result->buflen) > + (sizeof(*gscan_result) + WL_SCAN_IE_LEN_MAX))) { DHD_ERROR(("%s: invalid gscan buflen:%u\n", __FUNCTION__, - dtoh32(gscan_result->buflen))); + dtoh32(gscan_result->buflen))); goto exit; } bi = &gscan_result->bss_info[0].info; bi_length = dtoh32(bi->length); if (bi_length != (dtoh32(gscan_result->buflen) - - WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { + WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) { DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } @@ -3758,31 +3993,31 @@ goto exit; } - mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi_ie_length; - result = kmalloc(mem_needed, GFP_KERNEL); - + mem_needed = OFFSETOF(wifi_gscan_full_result_t, ie_data) + bi->ie_length; + result = (wifi_gscan_full_result_t *)MALLOC(dhd->osh, mem_needed); if (!result) { DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n", - __FUNCTION__, mem_needed)); + __FUNCTION__, mem_needed)); goto exit; } - memcpy(result->ssid, bi->SSID, bi->SSID_len); - result->ssid[bi->SSID_len] = '\0'; + result->scan_ch_bucket = gscan_result->scan_ch_bucket; + memcpy(result->fixed.ssid, bi->SSID, bi->SSID_len); + result->fixed.ssid[bi->SSID_len] = '\0'; channel = wf_chspec_ctlchan(bi->chanspec); - result->channel = wf_channel2mhz(channel, + result->fixed.channel = wf_channel2mhz(channel, (channel <= CH_MAX_2G_CHANNEL? WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - result->rssi = (int32) bi->RSSI; - result->rtt = 0; - result->rtt_sd = 0; + result->fixed.rssi = (int32) bi->RSSI; + result->fixed.rtt = 0; + result->fixed.rtt_sd = 0; get_monotonic_boottime(&ts); - result->ts = (uint64) TIMESPEC_TO_US(ts); - result->beacon_period = dtoh16(bi->beacon_period); - result->capability = dtoh16(bi->capability); + result->fixed.ts = (uint64) TIMESPEC_TO_US(ts); + result->fixed.beacon_period = dtoh16(bi->beacon_period); + result->fixed.capability = dtoh16(bi->capability); result->ie_length = bi_ie_length; - memcpy(&result->macaddr, &bi->BSSID, ETHER_ADDR_LEN); - memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi->ie_length); + memcpy(&result->fixed.macaddr, &bi->BSSID, ETHER_ADDR_LEN); + memcpy(result->ie_data, ((uint8 *)bi + bi_ie_offset), bi_ie_length); *size = mem_needed; exit: return result; @@ -3803,87 +4038,96 @@ return NULL; gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - if (event == WLC_E_PFN_SSID_EXT) { - wl_pfn_ssid_ext_result_t *evt_data; - evt_data = (wl_pfn_ssid_ext_result_t *) data; + if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { + wl_pfn_scanresults_v1_t *pfn_result = (wl_pfn_scanresults_v1_t *)data; + wl_pfn_scanresults_v2_t *pfn_result_v2 = (wl_pfn_scanresults_v2_t *)data; + wl_pfn_net_info_v1_t *net; + wl_pfn_net_info_v2_t *net_v2; - if (evt_data->version != PFN_SSID_EXT_VERSION) { - DHD_PNO(("ePNO event: Incorrect version %d %d\n", evt_data->version, - PFN_SSID_EXT_VERSION)); + if (pfn_result->version == PFN_SCANRESULT_VERSION_V1) { + if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT_V1)) { + DHD_ERROR(("%s event %d: wrong pfn v1 results count %d\n", + __FUNCTION__, event, pfn_result->count)); + return NULL; + } + count = pfn_result->count; + mem_needed = sizeof(dhd_epno_results_t) * count; + results = (dhd_epno_results_t *)MALLOC(dhd->osh, mem_needed); + if (!results) { + DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, + mem_needed)); + return NULL; + } + for (i = 0; i < count; i++) { + net = &pfn_result->netinfo[i]; + results[i].rssi = net->RSSI; + results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, + (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? + WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; + results[i].ssid_len = min(net->pfnsubnet.SSID_len, + (uint8)DOT11_MAX_SSID_LEN); + bssid = &results[i].bssid; + memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); + if (!net->pfnsubnet.SSID_len) { + DHD_ERROR(("%s: Gscan results indexing is not" + " supported in version 1 \n", __FUNCTION__)); + MFREE(dhd->osh, results, mem_needed); + return NULL; + } else { + memcpy(results[i].ssid, net->pfnsubnet.SSID, + results[i].ssid_len); + } + memcpy(ssid, results[i].ssid, results[i].ssid_len); + ssid[results[i].ssid_len] = '\0'; + DHD_PNO(("ssid - %s bssid "MACDBG" ch %d rssi %d flags %d\n", + ssid, MAC2STRDBG(bssid->octet), results[i].channel, + results[i].rssi, results[i].flags)); + } + } else if (pfn_result_v2->version == PFN_SCANRESULT_VERSION_V2) { + if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT_V2)) { + DHD_ERROR(("%s event %d: wrong pfn v2 results count %d\n", + __FUNCTION__, event, pfn_result->count)); + return NULL; + } + count = pfn_result_v2->count; + mem_needed = sizeof(dhd_epno_results_t) * count; + results = (dhd_epno_results_t *)MALLOC(dhd->osh, mem_needed); + if (!results) { + DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, + mem_needed)); + return NULL; + } + for (i = 0; i < count; i++) { + net_v2 = &pfn_result_v2->netinfo[i]; + results[i].rssi = net_v2->RSSI; + results[i].channel = wf_channel2mhz(net_v2->pfnsubnet.channel, + (net_v2->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? + WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; + results[i].ssid_len = min(net_v2->pfnsubnet.SSID_len, + (uint8)DOT11_MAX_SSID_LEN); + bssid = &results[i].bssid; + memcpy(bssid, &net_v2->pfnsubnet.BSSID, ETHER_ADDR_LEN); + if (!net_v2->pfnsubnet.SSID_len) { + dhd_pno_idx_to_ssid(gscan_params, &results[i], + net_v2->pfnsubnet.u.index); + } else { + memcpy(results[i].ssid, net_v2->pfnsubnet.u.SSID, + results[i].ssid_len); + } + memcpy(ssid, results[i].ssid, results[i].ssid_len); + ssid[results[i].ssid_len] = '\0'; + DHD_PNO(("ssid - %s bssid "MACDBG" ch %d rssi %d flags %d\n", + ssid, MAC2STRDBG(bssid->octet), results[i].channel, + results[i].rssi, results[i].flags)); + } + } else { + DHD_ERROR(("%s event %d: Incorrect version %d , not supported\n", + __FUNCTION__, event, pfn_result->version)); return NULL; - } - count = evt_data->count; - mem_needed = sizeof(dhd_epno_results_t) * count; - results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); - if (!results) { - DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, - mem_needed)); - return NULL; - } - DHD_ERROR(("Rx'ed WLC_E_PFN_SSID_EXT event: %d results\n", count)); - for (i = 0; i < count; i++) { - results[i].rssi = evt_data->net[i].rssi; - results[i].channel = wf_channel2mhz(evt_data->net[i].channel, - (evt_data->net[i].channel <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - results[i].flags = evt_data->net[i].flags; - dhd_pno_idx_to_ssid(gscan_params, &results[i], - evt_data->net[i].index); - memcpy(ssid, results[i].ssid, results[i].ssid_len); - bssid = &results[i].bssid; - memcpy(bssid, &evt_data->net[i].bssid, ETHER_ADDR_LEN); - ssid[results[i].ssid_len] = '\0'; - DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " - "idx %d ch %d rssi %d flags %d\n", ssid, - bssid->octet[0], bssid->octet[1], - bssid->octet[2], bssid->octet[3], - bssid->octet[4], bssid->octet[5], - evt_data->net[i].index, results[i].channel, - results[i].rssi, results[i].flags)); - } - } else if (event == WLC_E_PFN_NET_FOUND || event == WLC_E_PFN_NET_LOST) { - wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data; - wl_pfn_net_info_t *net; - - if (pfn_result->version != PFN_SCANRESULT_VERSION) { - DHD_ERROR(("%s event %d: Incorrect version %d %d\n", __FUNCTION__, event, - pfn_result->version, PFN_SCANRESULT_VERSION)); - return NULL; - } - if ((pfn_result->count == 0) || (pfn_result->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s event %d: wrong pfn results count %d\n", - __FUNCTION__, event, pfn_result->count)); - return NULL; - } - count = pfn_result->count; - mem_needed = sizeof(dhd_epno_results_t) * count; - results = (dhd_epno_results_t *) kmalloc(mem_needed, GFP_KERNEL); - if (!results) { - DHD_ERROR(("%s: Can't malloc %d bytes for results\n", __FUNCTION__, - mem_needed)); - return NULL; - } - for (i = 0; i < count; i++) { - net = &pfn_result->netinfo[i]; - results[i].rssi = net->RSSI; - results[i].channel = wf_channel2mhz(net->pfnsubnet.channel, - (net->pfnsubnet.channel <= CH_MAX_2G_CHANNEL ? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - results[i].flags = (event == WLC_E_PFN_NET_FOUND) ? - WL_PFN_SSID_EXT_FOUND: WL_PFN_SSID_EXT_LOST; - results[i].ssid_len = min(net->pfnsubnet.SSID_len, - (uint8)DOT11_MAX_SSID_LEN); - bssid = &results[i].bssid; - memcpy(bssid, &net->pfnsubnet.BSSID, ETHER_ADDR_LEN); - memcpy(results[i].ssid, net->pfnsubnet.SSID, results[i].ssid_len); - memcpy(ssid, results[i].ssid, results[i].ssid_len); - ssid[results[i].ssid_len] = '\0'; - DHD_PNO(("ssid - %s bssid %02x:%02x:%02x:%02x:%02x:%02x " - "ch %d rssi %d flags %d\n", ssid, - bssid->octet[0], bssid->octet[1], - bssid->octet[2], bssid->octet[3], - bssid->octet[4], bssid->octet[5], - results[i].channel, results[i].rssi, results[i].flags)); } } *size = mem_needed; @@ -3892,83 +4136,170 @@ void * dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, - int *send_evt_bytes, hotlist_type_t type) + int *send_evt_bytes, hotlist_type_t type, u32 *buf_len) { void *ptr = NULL; dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); struct dhd_pno_gscan_params *gscan_params; - wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data; + wl_pfn_scanresults_v1_t *results_v1 = (wl_pfn_scanresults_v1_t *)event_data; + wl_pfn_scanresults_v2_t *results_v2 = (wl_pfn_scanresults_v2_t *)event_data; wifi_gscan_result_t *hotlist_found_array; - wl_pfn_net_info_t *plnetinfo; + wl_pfn_net_info_v1_t *pnetinfo; + wl_pfn_net_info_v2_t *pnetinfo_v2; gscan_results_cache_t *gscan_hotlist_cache; - int malloc_size = 0, i, total = 0; + u32 malloc_size = 0, i, total = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) + struct timespec64 tm_spec; +#else + struct timespec tm_spec; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) */ + uint16 fwstatus; + uint16 fwcount; - gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + /* Static asserts in _dhd_pno_get_for_batch() above guarantee the v1 and v2 + * net_info and subnet_info structures are compatible in size and SSID offset, + * allowing v1 to be safely used in the code below except for lscanresults + * fields themselves (status, count, offset to netinfo). + */ - if ((results->count == 0) || (results->count > EVENT_MAX_NETCNT)) { - DHD_ERROR(("%s: wrong result count:%d\n", __FUNCTION__, results->count)); - *send_evt_bytes = 0; - return ptr; - } + *buf_len = 0; + if (results_v1->version == PFN_SCANRESULTS_VERSION_V1) { + fwstatus = results_v1->status; + fwcount = results_v1->count; + pnetinfo = &results_v1->netinfo[0]; - malloc_size = sizeof(gscan_results_cache_t) + - ((results->count - 1) * sizeof(wifi_gscan_result_t)); - gscan_hotlist_cache = (gscan_results_cache_t *) kmalloc(malloc_size, GFP_KERNEL); + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); - if (!gscan_hotlist_cache) { - DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); - *send_evt_bytes = 0; - return ptr; - } - - if (type == HOTLIST_FOUND) { - gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; - gscan_params->gscan_hotlist_found = gscan_hotlist_cache; - DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, results->count)); - } else { - gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; - gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; - DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, results->count)); - } - - gscan_hotlist_cache->tot_count = results->count; - gscan_hotlist_cache->tot_consumed = 0; - plnetinfo = results->netinfo; - - for (i = 0; i < results->count; i++, plnetinfo++) { - hotlist_found_array = &gscan_hotlist_cache->results[i]; - hotlist_found_array->channel = wf_channel2mhz(plnetinfo->pfnsubnet.channel, - (plnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? - WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); - hotlist_found_array->rssi = (int32) plnetinfo->RSSI; - /* Info not available & not expected */ - hotlist_found_array->beacon_period = 0; - hotlist_found_array->capability = 0; - hotlist_found_array->ie_length = 0; - - hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp); - if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", - plnetinfo->pfnsubnet.SSID_len)); - plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + if (!fwcount || (fwcount > EVENT_MAX_NETCNT_V1)) { + DHD_ERROR(("%s: wrong v1 fwcount:%d\n", __FUNCTION__, fwcount)); + *send_evt_bytes = 0; + return ptr; } - memcpy(hotlist_found_array->ssid, plnetinfo->pfnsubnet.SSID, - plnetinfo->pfnsubnet.SSID_len); - hotlist_found_array->ssid[plnetinfo->pfnsubnet.SSID_len] = '\0'; - memcpy(&hotlist_found_array->macaddr, &plnetinfo->pfnsubnet.BSSID, ETHER_ADDR_LEN); - DHD_PNO(("\t%s %02x:%02x:%02x:%02x:%02x:%02x rssi %d\n", hotlist_found_array->ssid, - hotlist_found_array->macaddr.octet[0], - hotlist_found_array->macaddr.octet[1], - hotlist_found_array->macaddr.octet[2], - hotlist_found_array->macaddr.octet[3], - hotlist_found_array->macaddr.octet[4], - hotlist_found_array->macaddr.octet[5], - hotlist_found_array->rssi)); + get_monotonic_boottime(&tm_spec); + malloc_size = sizeof(gscan_results_cache_t) + + ((fwcount - 1) * sizeof(wifi_gscan_result_t)); + gscan_hotlist_cache = (gscan_results_cache_t *)MALLOC(dhd->osh, malloc_size); + if (!gscan_hotlist_cache) { + DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); + *send_evt_bytes = 0; + return ptr; + } + + *buf_len = malloc_size; + if (type == HOTLIST_FOUND) { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; + gscan_params->gscan_hotlist_found = gscan_hotlist_cache; + DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, fwcount)); + } else { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; + gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; + DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, fwcount)); + } + + gscan_hotlist_cache->tot_count = fwcount; + gscan_hotlist_cache->tot_consumed = 0; + + for (i = 0; i < fwcount; i++, pnetinfo++) { + hotlist_found_array = &gscan_hotlist_cache->results[i]; + memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t)); + hotlist_found_array->channel = wf_channel2mhz(pnetinfo->pfnsubnet.channel, + (pnetinfo->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + hotlist_found_array->rssi = (int32) pnetinfo->RSSI; + + hotlist_found_array->ts = + convert_fw_rel_time_to_systime(&tm_spec, + (pnetinfo->timestamp * 1000)); + if (pnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", + pnetinfo->pfnsubnet.SSID_len)); + pnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(hotlist_found_array->ssid, pnetinfo->pfnsubnet.SSID, + pnetinfo->pfnsubnet.SSID_len); + hotlist_found_array->ssid[pnetinfo->pfnsubnet.SSID_len] = '\0'; + + memcpy(&hotlist_found_array->macaddr, &pnetinfo->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + DHD_PNO(("\t%s "MACDBG" rssi %d\n", + hotlist_found_array->ssid, + MAC2STRDBG(hotlist_found_array->macaddr.octet), + hotlist_found_array->rssi)); + } + } else if (results_v2->version == PFN_SCANRESULTS_VERSION_V2) { + fwstatus = results_v2->status; + fwcount = results_v2->count; + pnetinfo_v2 = (wl_pfn_net_info_v2_t*)&results_v2->netinfo[0]; + + gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan); + + if (!fwcount || (fwcount > EVENT_MAX_NETCNT_V2)) { + DHD_ERROR(("%s: wrong v2 fwcount:%d\n", __FUNCTION__, fwcount)); + *send_evt_bytes = 0; + return ptr; + } + + get_monotonic_boottime(&tm_spec); + malloc_size = sizeof(gscan_results_cache_t) + + ((fwcount - 1) * sizeof(wifi_gscan_result_t)); + gscan_hotlist_cache = + (gscan_results_cache_t *)MALLOC(dhd->osh, malloc_size); + if (!gscan_hotlist_cache) { + DHD_ERROR(("%s Cannot Malloc %d bytes!!\n", __FUNCTION__, malloc_size)); + *send_evt_bytes = 0; + return ptr; + } + *buf_len = malloc_size; + if (type == HOTLIST_FOUND) { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_found; + gscan_params->gscan_hotlist_found = gscan_hotlist_cache; + DHD_PNO(("%s enter, FOUND results count %d\n", __FUNCTION__, fwcount)); + } else { + gscan_hotlist_cache->next = gscan_params->gscan_hotlist_lost; + gscan_params->gscan_hotlist_lost = gscan_hotlist_cache; + DHD_PNO(("%s enter, LOST results count %d\n", __FUNCTION__, fwcount)); + } + + gscan_hotlist_cache->tot_count = fwcount; + gscan_hotlist_cache->tot_consumed = 0; + gscan_hotlist_cache->scan_ch_bucket = results_v2->scan_ch_bucket; + + for (i = 0; i < fwcount; i++, pnetinfo_v2++) { + hotlist_found_array = &gscan_hotlist_cache->results[i]; + memset(hotlist_found_array, 0, sizeof(wifi_gscan_result_t)); + hotlist_found_array->channel = + wf_channel2mhz(pnetinfo_v2->pfnsubnet.channel, + (pnetinfo_v2->pfnsubnet.channel <= CH_MAX_2G_CHANNEL? + WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G)); + hotlist_found_array->rssi = (int32) pnetinfo_v2->RSSI; + + hotlist_found_array->ts = + convert_fw_rel_time_to_systime(&tm_spec, + (pnetinfo_v2->timestamp * 1000)); + if (pnetinfo_v2->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", + pnetinfo_v2->pfnsubnet.SSID_len)); + pnetinfo_v2->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } + memcpy(hotlist_found_array->ssid, pnetinfo_v2->pfnsubnet.u.SSID, + pnetinfo_v2->pfnsubnet.SSID_len); + hotlist_found_array->ssid[pnetinfo_v2->pfnsubnet.SSID_len] = '\0'; + + memcpy(&hotlist_found_array->macaddr, &pnetinfo_v2->pfnsubnet.BSSID, + ETHER_ADDR_LEN); + DHD_PNO(("\t%s "MACDBG" rssi %d\n", + hotlist_found_array->ssid, + MAC2STRDBG(hotlist_found_array->macaddr.octet), + hotlist_found_array->rssi)); + } + } else { + DHD_ERROR(("%s: event version %d not supported\n", + __FUNCTION__, results_v1->version)); + *send_evt_bytes = 0; + return ptr; } - - - if (results->status == PFN_COMPLETE) { + if (fwstatus == PFN_COMPLETE) { ptr = (void *) gscan_hotlist_cache; while (gscan_hotlist_cache) { total += gscan_hotlist_cache->tot_count; @@ -3980,11 +4311,12 @@ return ptr; } #endif /* GSCAN_SUPPORT */ + int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) { int err = BCME_OK; - uint status, event_type, flags, datalen; + uint event_type; dhd_pno_status_info_t *_pno_state; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); @@ -3995,9 +4327,6 @@ goto exit; } event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - datalen = ntoh32(event->datalen); DHD_PNO(("%s enter : event_type :%d\n", __FUNCTION__, event_type)); switch (event_type) { case WLC_E_PFN_BSSID_NET_FOUND: @@ -4009,7 +4338,11 @@ { struct dhd_pno_batch_params *params_batch; params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + if (!swait_active(&_pno_state->get_batch_done.wait)) +#else if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { +#endif/* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */ DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); params_batch->get_batch.buf = NULL; params_batch->get_batch.bufsize = 0; @@ -4053,13 +4386,13 @@ #ifdef GSCAN_SUPPORT init_waitqueue_head(&_pno_state->batch_get_wait); #endif /* GSCAN_SUPPORT */ - buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); + buf = MALLOC(dhd->osh, WLC_IOCTL_SMLEN); if (!buf) { DHD_ERROR((":%s buf alloc err.\n", __FUNCTION__)); return BCME_NOMEM; } err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, buf, WLC_IOCTL_SMLEN, - FALSE); + FALSE); if (err == BCME_UNSUPPORTED) { _pno_state->wls_supported = FALSE; DHD_INFO(("Current firmware doesn't support" @@ -4069,10 +4402,9 @@ __FUNCTION__)); } exit: - kfree(buf); + MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN); return err; } - int dhd_pno_deinit(dhd_pub_t *dhd) { int err = BCME_OK; @@ -4093,7 +4425,7 @@ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) { _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS]; mutex_lock(&_pno_state->pno_mutex); - dhd_pno_reset_cfg_gscan(_params, _pno_state, GSCAN_FLUSH_ALL_CFG); + dhd_pno_reset_cfg_gscan(dhd, _params, _pno_state, GSCAN_FLUSH_ALL_CFG); mutex_unlock(&_pno_state->pno_mutex); } #endif /* GSCAN_SUPPORT */ @@ -4108,4 +4440,5 @@ dhd->pno_state = NULL; return err; } +#endif /* OEM_ANDROID */ #endif /* PNO_SUPPORT */ -- Gitblit v1.6.2