diff --git a/os_if/linux/scan/inc/wlan_cfg80211_scan.h b/os_if/linux/scan/inc/wlan_cfg80211_scan.h index c1c5d8cbe610..69cbc99691bc 100644 --- a/os_if/linux/scan/inc/wlan_cfg80211_scan.h +++ b/os_if/linux/scan/inc/wlan_cfg80211_scan.h @@ -28,10 +28,15 @@ #include #include #include +#include #include #include #include + +/* Max number of scans allowed from userspace */ +#define WLAN_MAX_SCAN_COUNT 8 + #ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS /* GPS application requirement */ #define QCOM_VENDOR_IE_ID 221 @@ -40,6 +45,11 @@ #define QCOM_OUI3 0xC6 #define QCOM_VENDOR_IE_AGE_TYPE 0x100 #define QCOM_VENDOR_IE_AGE_LEN (sizeof(qcom_ie_age) - 2) +#define SCAN_DONE_EVENT_BUF_SIZE 4096 +#define INVAL_SCAN_ID 0xFFFFFFFF +#define INVAL_VDEV_ID 0xFFFFFFFF +#define INVAL_PDEV_ID 0xFFFFFFFF + /** * typedef struct qcom_ie_age - age ie @@ -72,16 +82,55 @@ typedef struct { /** * struct osif_scan_pdev - OS scan private strcutre * scan_req_q: Scan request queue + * req_id: Scan request Id */ struct osif_scan_pdev{ qdf_list_t scan_req_q; + wlan_scan_requester req_id; +}; + +/* + * enum scan_source - scan request source + * @NL_SCAN: Scan initiated from NL + * @VENDOR_SCAN: Scan intiated from vendor command + */ +enum scan_source { + NL_SCAN, + VENDOR_SCAN, }; +/** + * struct scan_req - Scan Request entry + * @node : List entry element + * @scan_request: scan request holder + * @scan_id: scan identifier used across host layers which is generated at WMI + * @source: scan request originator (NL/Vendor scan) + * + * Scan request linked list element + */ +struct scan_req { + qdf_list_node_t node; + struct cfg80211_scan_request *scan_request; + uint32_t scan_id; + uint8_t source; +}; + + +/** + * wlan_cfg80211_scan_priv_init() - API to initialize cfg80211 scan + * @pdev: Pointer to net device + * + * API to initialize cfg80211 scan module. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cfg80211_scan_priv_init(struct wlan_objmgr_pdev *pdev); + /** * wlan_cfg80211_scan() - API to process cfg80211 scan request - * @wiphy: Pointer to wiphy - * @dev: Pointer to net device + * @pdev: Pointer to pdev * @request: Pointer to scan request + * @source: source of scan request * * API to trigger scan and update cfg80211 scan database. * scan dump command can be used to fetch scan results @@ -89,11 +138,9 @@ struct osif_scan_pdev{ * * Return: 0 for success, non zero for failure */ -int wlan_cfg80211_scan(struct wiphy *wiphy, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) - struct net_device *dev, -#endif - struct cfg80211_scan_request *request); +int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, + struct cfg80211_scan_request *request, + uint8_t source); /** * wlan_cfg80211_inform_bss_frame() - API to inform beacon to cfg80211 @@ -107,4 +154,44 @@ int wlan_cfg80211_scan(struct wiphy *wiphy, */ void wlan_cfg80211_inform_bss_frame(struct wlan_objmgr_pdev *pdev, struct scan_cache_entry *scan_params); + +/** + * wlan_vendor_abort_scan() - API to vendor abort scan + * @pdev: Pointer to pdev + * @data: pointer to data + * @data_len: Data length + * + * API to abort scan through vendor command + * + * Return: 0 for success, non zero for failure + */ +int wlan_vendor_abort_scan(struct wlan_objmgr_pdev *pdev, + const void *data, int data_len); + +/** + * wlan_cfg80211_abort_scan() - API to abort scan through cfg80211 + * @pdev: Pointer to pdev + * + * API to abort scan through cfg80211 request + * + * Return: 0 for success, non zero for failure + */ +int wlan_cfg80211_abort_scan(struct wlan_objmgr_pdev *pdev); + +/** + * wlan_abort_scan() - Generic API to abort scan request + * @pdev: Pointer to pdev + * @pdev_id: pdev id + * @vdev_id: vdev id + * @scan_id: scan id + * + * Generic API to abort scans + * + * Return: 0 for success, non zero for failure + */ +QDF_STATUS wlan_abort_scan(struct wlan_objmgr_pdev *pdev, + uint32_t pdev_id, + uint32_t vdev_id, + wlan_scan_id scan_id); + #endif diff --git a/os_if/linux/scan/src/wlan_cfg80211_scan.c b/os_if/linux/scan/src/wlan_cfg80211_scan.c index 1fcf5ce3b0cf..f1819096e435 100644 --- a/os_if/linux/scan/src/wlan_cfg80211_scan.c +++ b/os_if/linux/scan/src/wlan_cfg80211_scan.c @@ -20,19 +20,640 @@ * DOC: defines driver functions interfacing with linux kernel */ -#include -#include -#include +#include +#include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include -int wlan_cfg80211_scan(struct wiphy *wiphy, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) - struct net_device *dev, -#endif - struct cfg80211_scan_request *request) +/** + * wlan_scan_request_enqueue() - enqueue Scan Request + * @pdev: pointer to pdev object + * @req: Pointer to the scan request + * @source: source of the scan request + * @scan_id: scan identifier + * + * Enqueue scan request in the global scan list.This list + * stores the active scan request information. + * + * Return: 0 on success, error number otherwise + */ +static int wlan_scan_request_enqueue(struct wlan_objmgr_pdev *pdev, + struct cfg80211_scan_request *req, + uint8_t source, uint32_t scan_id) { + struct scan_req *scan_req; + QDF_STATUS status; + struct pdev_osif_priv *osif_ctx; + struct osif_scan_pdev *osif_scan; + + scan_req = qdf_mem_malloc(sizeof(*scan_req)); + if (NULL == scan_req) { + cfg80211_alert("malloc failed for Scan req"); + return -ENOMEM; + } + + /* Get NL global context from objmgr*/ + osif_ctx = wlan_pdev_get_ospriv(pdev); + osif_scan = osif_ctx->osif_scan; + scan_req->scan_request = req; + scan_req->source = source; + scan_req->scan_id = scan_id; + + status = qdf_list_insert_back(&osif_scan->scan_req_q, + &scan_req->node); + + if (QDF_STATUS_SUCCESS != status) { + cfg80211_err("Failed to enqueue Scan Req"); + qdf_mem_free(scan_req); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_scan_request_dequeue() - dequeue scan request + * @nl_ctx: Global HDD context + * @scan_id: scan id + * @req: scan request + * @source : returns source of the scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_scan_request_dequeue( + struct wlan_objmgr_pdev *pdev, + uint32_t scan_id, struct cfg80211_scan_request **req, uint8_t *source) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct scan_req *scan_req; + qdf_list_node_t *node = NULL, *next_node = NULL; + struct pdev_osif_priv *osif_ctx; + struct osif_scan_pdev *scan_priv; + + cfg80211_info("Dequeue Scan id: %d", scan_id); + + if ((source == NULL) || (req == NULL)) { + cfg80211_err("source or request is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* Get NL global context from objmgr*/ + osif_ctx = wlan_pdev_get_ospriv(pdev); + if (!osif_ctx) { + cfg80211_err("Failed to retrieve osif context"); + return status; + } + scan_priv = osif_ctx->osif_scan; + + if (qdf_list_empty(&scan_priv->scan_req_q)) { + cfg80211_info("Scan List is empty"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&scan_priv->scan_req_q, &next_node)) { + cfg80211_err("Failed to remove Scan Req from queue"); + return QDF_STATUS_E_FAILURE; + } + + do { + node = next_node; + scan_req = qdf_container_of(node, struct scan_req, + node); + if (scan_req->scan_id == scan_id) { + status = qdf_list_remove_node(&scan_priv->scan_req_q, + node); + if (status == QDF_STATUS_SUCCESS) { + *req = scan_req->scan_request; + *source = scan_req->source; + qdf_mem_free(scan_req); + cfg80211_info("removed Scan id: %d, req = %p, pending scans %d", + scan_id, req, + qdf_list_size(&scan_priv->scan_req_q)); + return QDF_STATUS_SUCCESS; + } else { + cfg80211_err("Failed to remove node scan id %d, pending scans %d", + scan_id, + qdf_list_size(&scan_priv->scan_req_q)); + return status; + } + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&scan_priv->scan_req_q, node, &next_node)); + + cfg80211_err("Failed to find scan id %d", scan_id); + + return status; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +/** + * wlan_cfg80211_scan_done() - Scan completed callback to cfg80211 + * + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void wlan_cfg80211_scan_done(struct cfg80211_scan_request *req, + bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted + }; + + if (req->wdev->netdev->flags & IFF_UP) + cfg80211_scan_done(req, &info); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +/** + * wlan_cfg80211_scan_done() - Scan completed callback to cfg80211 + * + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void wlan_cfg80211_scan_done(struct cfg80211_scan_request *req, + bool aborted) +{ + if (req->wdev->netdev->flags & IFF_UP) + cfg80211_scan_done(req, aborted); +} +#endif + +/** + * wlan_vendor_scan_callback() - Scan completed callback event + * + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function sends scan completed callback event to NL. + * + * Return: none + */ +static void wlan_vendor_scan_callback(struct cfg80211_scan_request *req, + bool aborted) +{ + struct sk_buff *skb; + struct nlattr *attr; + int i; + uint8_t scan_status; + uint64_t cookie; + + skb = cfg80211_vendor_event_alloc(req->wdev->wiphy, req->wdev, + SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX, + GFP_KERNEL); + + if (!skb) { + cfg80211_err("skb alloc failed"); + qdf_mem_free(req); + return; + } + + cookie = (uintptr_t)req; + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) { + if (nla_put(skb, i, req->ssids[i].ssid_len, req->ssids[i].ssid)) + goto nla_put_failure; + } + nla_nest_end(skb, attr); + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) { + if (nla_put_u32(skb, i, req->channels[i]->center_freq)) + goto nla_put_failure; + } + nla_nest_end(skb, attr); + + if (req->ie && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len, + req->ie)) + goto nla_put_failure; + + if (req->flags && + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags)) + goto nla_put_failure; + + if (wlan_cfg80211_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) + goto nla_put_failure; + + scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED : + VENDOR_SCAN_STATUS_NEW_RESULTS; + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status)) + goto nla_put_failure; + + cfg80211_vendor_event(skb, GFP_KERNEL); + qdf_mem_free(req); + + return; + +nla_put_failure: + kfree_skb(skb); + qdf_mem_free(req); +} + + +/** + * wlan_cfg80211_scan_done_callback() - scan done callback function called after + * scan is finished + * @pContext: Pointer to context + * @scanId: Scan Id + * @status: Scan status + * + * Return: QDF status + */ +static void wlan_cfg80211_scan_done_callback( + struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *args) +{ + struct cfg80211_scan_request *req = NULL; + bool aborted = false; + uint32_t scan_id = event->scan_id; + uint8_t source = NL_SCAN; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + + cfg80211_err("called with ID = %d, reason = %d", + scan_id, event->reason); + + /* + * cfg80211_scan_done informing NL80211 about completion + * of scanning + */ + if ((event->type == SCAN_EVENT_TYPE_COMPLETED) && + ((event->reason == SCAN_REASON_CANCELLED) || + (event->reason == SCAN_REASON_TIMEDOUT) || + (event->reason == SCAN_REASON_INTERNAL_FAILURE))) { + aborted = true; + } else if ((event->type == SCAN_EVENT_TYPE_COMPLETED) && + (event->reason == SCAN_REASON_COMPLETED)) + aborted = false; + else + /* cfg80211 is not interested on all other scan events */ + return; + + pdev = wlan_vdev_get_pdev(vdev); + status = wlan_scan_request_dequeue(pdev, scan_id, &req, &source); + if (QDF_IS_STATUS_ERROR(status)) { + cfg80211_err("Dequeue of scan request failed ID: %d", scan_id); + return; + } + + /* + * Scan can be triggred from NL or vendor scan + * - If scan is triggered from NL then cfg80211 scan done should be + * called to updated scan completion to NL. + * - If scan is triggred through vendor command then + * scan done event will be posted + */ + if (NL_SCAN == source) + wlan_cfg80211_scan_done(req, aborted); + else + wlan_vendor_scan_callback(req, aborted); +} + +QDF_STATUS wlan_cfg80211_scan_priv_init(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_osif_priv *osif_priv; + struct osif_scan_pdev *scan_priv; + struct wlan_objmgr_psoc *psoc; + wlan_scan_requester req_id; + + wlan_pdev_obj_lock(pdev); + psoc = wlan_pdev_get_psoc(pdev); + wlan_pdev_obj_unlock(pdev); + req_id = ucfg_scan_register_requester(psoc, "HDD", + wlan_cfg80211_scan_done_callback, NULL); + + osif_priv = wlan_pdev_get_ospriv(pdev); + scan_priv = qdf_mem_malloc(sizeof(*scan_priv)); + if (!scan_priv) { + cfg80211_err("failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + /* Initialize the scan request queue */ + osif_priv->osif_scan = scan_priv; + qdf_list_create(&scan_priv->scan_req_q, WLAN_MAX_SCAN_COUNT); + scan_priv->req_id = req_id; + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_cfg80211_scan() - Process scan request + * @pdev: pdev object pointer + * @request: scan request + * @source : returns source of the scan request + * + * Return: 0 on success, error number otherwise + */ +int wlan_cfg80211_scan(struct wlan_objmgr_pdev *pdev, + struct cfg80211_scan_request *request, + uint8_t source) +{ + struct net_device *dev = request->wdev->netdev; + struct scan_start_request *req; + struct wlan_ssid *pssid; + uint8_t i; + int status; + uint8_t num_chan = 0, channel; + struct wlan_objmgr_vdev *vdev; + wlan_scan_requester req_id; + struct pdev_osif_priv *osif_priv; + struct wlan_objmgr_psoc *psoc; + wlan_scan_id scan_id; + + /* Get the vdev object */ + vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, dev->dev_addr, + WLAN_OSIF_ID); + if (vdev == NULL) { + cfg80211_err("vdev object is NULL"); + return -EIO; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + cfg80211_err("Invalid psoc object"); + return -EINVAL; + } + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + cfg80211_err("Failed to allocate scan request memory"); + return -EINVAL; + } + /* Initialize the scan global params */ + ucfg_scan_init_default_params(vdev, req); + + /* Get NL global context from objmgr*/ + osif_priv = wlan_pdev_get_ospriv(pdev); + req_id = osif_priv->osif_scan->req_id; + scan_id = ucfg_scan_get_scan_id(psoc); + if (!scan_id) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + cfg80211_err("Invalid scan id"); + qdf_mem_free(req); + return -EINVAL; + } + /* fill the scan request structure */ + req->vdev = vdev; + req->scan_req.scan_id = scan_id; + req->scan_req.scan_req_id = req_id; + /* + * Even though supplicant doesn't provide any SSIDs, n_ssids is + * set to 1. Because of this, driver is assuming that this is not + * wildcard scan and so is not aging out the scan results. + */ + if ((request->ssids) && (request->n_ssids == 1) && + ('\0' == request->ssids->ssid[0])) { + request->n_ssids = 0; + } + + if ((request->ssids) && (0 < request->n_ssids)) { + int j; + req->scan_req.num_ssids = request->n_ssids; + + /* copy all the ssid's and their length */ + for (j = 0; j < request->n_ssids; j++) { + pssid = &req->scan_req.ssid[j]; + /* get the ssid length */ + pssid->length = request->ssids[j].ssid_len; + qdf_mem_copy(pssid->ssid, + &request->ssids[j].ssid[0], + pssid->length); + pssid->ssid[pssid->length] = '\0'; + cfg80211_notice("SSID number %d: %s", j, + pssid->ssid); + } + } + if (request->ssids || + (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE)) + req->scan_req.scan_f_passive = false; + + if (!request->no_cck) { + req->scan_req.scan_f_cck_rates = true; + if (!req->scan_req.num_ssids) + req->scan_req.scan_f_bcast_probe = true; + req->scan_req.scan_f_add_tpc_ie_in_probe = true; + req->scan_req.scan_f_filter_prb_req = true; + } + req->scan_req.scan_f_add_ds_ie_in_probe = true; + + qdf_mem_copy(&req->scan_req.bssid_list[0].bytes, request->bssid, + QDF_MAC_ADDR_SIZE); + if (request->n_channels) { + char chl[(request->n_channels * 5) + 1]; + int len = 0; + for (i = 0; i < request->n_channels; i++) { + channel = request->channels[i]->hw_value; + if (wlan_is_dsrc_channel(wlan_chan_to_freq(channel))) + continue; + len += snprintf(chl + len, 5, "%d ", channel); + req->scan_req.chan_list[i] = wlan_chan_to_freq(channel); + num_chan++; + } + cfg80211_notice("Channel-List: %s", chl); + cfg80211_notice("No. of Scan Channels: %d", num_chan); + } + if (!num_chan) { + cfg80211_err("Received zero non-dsrc channels"); + qdf_mem_free(req); + status = -EINVAL; + goto end; + } + req->scan_req.num_chan = num_chan; + + /* P2P increase the scan priority */ + if ((request->n_ssids == 1) && + (request->ssids != NULL) && + qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7)) + req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; + if (request->ie_len) { + req->scan_req.extraie.ptr = qdf_mem_malloc(request->ie_len); + if (!req->scan_req.extraie.ptr) { + cfg80211_err("Failed to allocate memory"); + status = -ENOMEM; + qdf_mem_free(req); + goto end; + } + req->scan_req.extraie.len = request->ie_len; + qdf_mem_copy(req->scan_req.extraie.ptr, request->ie, + request->ie_len); + } + /* Enqueue the scan request */ + wlan_scan_request_enqueue(pdev, request, source, req->scan_req.scan_id); + + status = ucfg_scan_start(req); + if (QDF_STATUS_SUCCESS != status) { + cfg80211_err("ucfg_scan_start returned error %d", status); + if (QDF_STATUS_E_RESOURCES == status) { + cfg80211_err("HO is in progress.So defer the scan by informing busy"); + status = -EBUSY; + } else { + status = -EIO; + } + } + + if (request->flags & NL80211_SCAN_FLAG_FLUSH) + ucfg_scan_flush_results(pdev, NULL); +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + return status; +} + +/** + * wlan_get_scanid() - API to get the scan id + * from the scan cookie attribute. + * @pdev: Pointer to pdev object + * @scan_id: Pointer to scan id + * @cookie : Scan cookie attribute + * + * API to get the scan id from the scan cookie attribute + * sent from supplicant by matching scan request. + * + * Return: 0 for success, non zero for failure + */ +static int wlan_get_scanid(struct wlan_objmgr_pdev *pdev, + uint32_t *scan_id, uint64_t cookie) +{ + struct scan_req *scan_req; + qdf_list_node_t *node = NULL; + qdf_list_node_t *ptr_node = NULL; + int ret = -EINVAL; + struct pdev_osif_priv *osif_ctx; + struct osif_scan_pdev *scan_priv; + + /* Get NL global context from objmgr*/ + osif_ctx = wlan_pdev_get_ospriv(pdev); + if (!osif_ctx) { + cfg80211_err("Failed to retrieve osif context"); + return ret; + } + scan_priv = osif_ctx->osif_scan; + if (qdf_list_empty(&scan_priv->scan_req_q)) { + cfg80211_err("Failed to retrieve scan id"); + return ret; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&scan_priv->scan_req_q, + &ptr_node)) { + return ret; + } + + do { + node = ptr_node; + scan_req = qdf_container_of(node, struct scan_req, node); + if (cookie == + (uintptr_t)(scan_req->scan_request)) { + *scan_id = scan_req->scan_id; + ret = 0; + break; + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&scan_priv->scan_req_q, + node, &ptr_node)); + + return ret; +} + +QDF_STATUS wlan_abort_scan(struct wlan_objmgr_pdev *pdev, + uint32_t pdev_id, uint32_t vdev_id, + wlan_scan_id scan_id) +{ + struct scan_cancel_request *req; + struct pdev_osif_priv *osif_ctx; + struct osif_scan_pdev *scan_priv; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + cfg80211_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + /* Get NL global context from objmgr*/ + osif_ctx = wlan_pdev_get_ospriv(pdev); + if (!osif_ctx) { + cfg80211_err("Failed to retrieve osif context"); + return QDF_STATUS_E_FAILURE; + } + + scan_priv = osif_ctx->osif_scan; + req->cancel_req.requester = scan_priv->req_id; + req->cancel_req.scan_id = scan_id; + req->cancel_req.pdev_id = pdev_id; + req->cancel_req.vdev_id = vdev_id; + if (scan_id != INVAL_SCAN_ID) + req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE; + if (vdev_id == INVAL_VDEV_ID) + req->cancel_req.req_type = WLAN_SCAN_CANCEL_PDEV_ALL; + else + req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL; + status = ucfg_scan_cancel(req); + if (QDF_IS_STATUS_ERROR(status)) + cfg80211_err("Cancel scan request failed"); + + return status; +} + +int wlan_cfg80211_abort_scan(struct wlan_objmgr_pdev *pdev) +{ + uint8_t pdev_id; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + wlan_abort_scan(pdev, pdev_id, INVAL_VDEV_ID, INVAL_SCAN_ID); + + return 0; +} + +int wlan_vendor_abort_scan(struct wlan_objmgr_pdev *pdev, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + int ret = -EINVAL; + wlan_scan_id scan_id; + uint64_t cookie; + uint8_t pdev_id; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data, + data_len, NULL)) { + cfg80211_err("Invalid ATTR"); + return ret; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) { + cookie = nla_get_u64( + tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); + ret = wlan_get_scanid(pdev, &scan_id, cookie); + if (ret != 0) + return ret; + wlan_abort_scan(pdev, pdev_id, INVAL_VDEV_ID, scan_id); + } return 0; } diff --git a/os_if/linux/wlan_cfg80211.h b/os_if/linux/wlan_cfg80211.h index 4bbd52f8463b..81844c77422d 100644 --- a/os_if/linux/wlan_cfg80211.h +++ b/os_if/linux/wlan_cfg80211.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -63,4 +64,18 @@ .doit = NULL \ }, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) +static inline int +wlan_cfg80211_nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put_u64(skb, attrtype, value); +} +#else +static inline int +wlan_cfg80211_nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put_u64_64bit(skb, attrtype, value, NL80211_ATTR_PAD); +} +#endif + #endif diff --git a/umac/cmn_services/inc/wlan_cmn.h b/umac/cmn_services/inc/wlan_cmn.h index 43cc3d34fbe7..82dbe053cafc 100644 --- a/umac/cmn_services/inc/wlan_cmn.h +++ b/umac/cmn_services/inc/wlan_cmn.h @@ -73,6 +73,18 @@ #define WLAN_PSOC_CREATE_TIMEOUT_CNT 300 /* 25 msec */ #define WLAN_PSOC_CREATE_TIMEOUT 25 +#define WLAN_24_GHZ_BASE_FREQ (2407) +#define WLAN_5_GHZ_BASE_FREQ (5000) +#define WLAN_24_GHZ_CHANNEL_6 (6) +#define WLAN_24_GHZ_CHANNEL_14 (14) +#define WLAN_24_GHZ_CHANNEL_15 (15) +#define WLAN_24_GHZ_CHANNEL_27 (27) +#define WLAN_5_GHZ_CHANNEL_170 (170) +#define WLAN_CHAN_SPACING_5MHZ (5) +#define WLAN_CHAN_SPACING_20MHZ (20) +#define WLAN_CHAN_14_FREQ (2484) +#define WLAN_CHAN_15_FREQ (2512) +#define WLAN_CHAN_170_FREQ (5852) /** * enum wlan_umac_comp_id - UMAC component id diff --git a/umac/cmn_services/utils/inc/wlan_utility.h b/umac/cmn_services/utils/inc/wlan_utility.h index 899d8fafd7c2..0905a099933d 100644 --- a/umac/cmn_services/utils/inc/wlan_utility.h +++ b/umac/cmn_services/utils/inc/wlan_utility.h @@ -23,4 +23,22 @@ #ifndef _WLAN_UTILITY_H_ #define _WLAN_UTILITY_H_ +#include + +/** + * wlan_chan_to_freq() - converts channel to frequency + * @chan: channel number + * + * @return frequency of the channel + */ +uint32_t wlan_chan_to_freq(uint8_t chan); + +/* + * wlan_is_dsrc_channel() - is the channel DSRC + * @center_freq: center freq of the channel + * + * Return: true if DSRC channel or false otherwise + */ +bool wlan_is_dsrc_channel(uint16_t center_freq); + #endif /* _WLAN_UTILITY_H_ */ diff --git a/umac/cmn_services/utils/src/wlan_utility.c b/umac/cmn_services/utils/src/wlan_utility.c index 9cb58474187b..29e4d7a59306 100644 --- a/umac/cmn_services/utils/src/wlan_utility.c +++ b/umac/cmn_services/utils/src/wlan_utility.c @@ -21,4 +21,30 @@ */ #include "wlan_utility.h" +#include +uint32_t wlan_chan_to_freq(uint8_t chan) +{ + /* ch 0 - ch 13 */ + if (chan < WLAN_24_GHZ_CHANNEL_14) + return WLAN_24_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ; + else if (chan == WLAN_24_GHZ_CHANNEL_14) + return WLAN_CHAN_14_FREQ; + else if (chan < WLAN_24_GHZ_CHANNEL_27) + /* ch 15 - ch 26 */ + return WLAN_CHAN_15_FREQ + + (chan - WLAN_24_GHZ_CHANNEL_15) * WLAN_CHAN_SPACING_20MHZ; + else if (chan == WLAN_5_GHZ_CHANNEL_170) + return WLAN_CHAN_170_FREQ; + else + return WLAN_5_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ; +} + +bool wlan_is_dsrc_channel(uint16_t center_freq) +{ + if (center_freq >= 5852 && + center_freq <= 5920) + return true; + + return false; +} diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h index a3f564e865cf..8d519b04045a 100644 --- a/umac/scan/core/src/wlan_scan_main.h +++ b/umac/scan/core/src/wlan_scan_main.h @@ -55,22 +55,22 @@ #define WLAN_SCAN_REQUESTER_ID_PREFIX 0x0000A000 #ifdef CONFIG_MCL -#define SCAN_ACTIVE_DWELL_TIME 20 -#define SCAN_PASSIVE_DWELL_TIME 100 -#define SCAN_MAX_REST_TIME 20 -#define SCAN_MIN_REST_TIME 0 -#define SCAN_BURST_DURATION 20 +#define SCAN_ACTIVE_DWELL_TIME 40 +#define SCAN_PASSIVE_DWELL_TIME 110 +#define SCAN_MAX_REST_TIME 100 +#define SCAN_MIN_REST_TIME 50 +#define SCAN_BURST_DURATION 0 #define SCAN_CONC_ACTIVE_DWELL_TIME 20 #define SCAN_CONC_PASSIVE_DWELL_TIME 100 #define SCAN_CONC_IDLE_TIME 25 #define SCAN_CONC_MAX_REST_TIME 20 #define SCAN_CONC_MIN_REST_TIME 10 -#define SCAN_REPEAT_PROBE_TIME 11 +#define SCAN_REPEAT_PROBE_TIME 20 #define SCAN_PROBE_SPACING_TIME 0 #define SCAN_PROBE_DELAY 0 #define SCAN_MAX_SCAN_TIME 30000 -#define SCAN_NUM_PROBES 3 -#define SCAN_NETWORK_IDLE_TIMEOUT 0 +#define SCAN_NUM_PROBES 2 +#define SCAN_NETWORK_IDLE_TIMEOUT 25 #else #define SCAN_ACTIVE_DWELL_TIME 105 #define SCAN_PASSIVE_DWELL_TIME 300 diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c index 1d2bfef126ed..be15e939495f 100644 --- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c @@ -346,6 +346,7 @@ wlan_scan_global_init(struct wlan_scan_obj *scan_obj) scan_obj->scan_def.idle_time = SCAN_NETWORK_IDLE_TIMEOUT; /* scan contrl flags */ scan_obj->scan_def.scan_f_passive = true; + scan_obj->scan_def.scan_f_ofdm_rates = true; scan_obj->scan_def.scan_f_2ghz = true; scan_obj->scan_def.scan_f_5ghz = true; /* scan event flags */ @@ -354,6 +355,9 @@ wlan_scan_global_init(struct wlan_scan_obj *scan_obj) scan_obj->scan_def.scan_ev_bss_chan = true; scan_obj->scan_def.scan_ev_foreign_chan = true; scan_obj->scan_def.scan_ev_dequeued = true; + scan_obj->scan_def.scan_ev_preempted = true; + scan_obj->scan_def.scan_ev_start_failed = true; + scan_obj->scan_def.scan_ev_restarted = true; /* init scan id seed */ qdf_atomic_init(&scan_obj->scan_ids);