diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-07-25 17:00:26 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-07-25 17:00:26 +0000 |
commit | d14e4d704776cca45d5675c3a86d356370760d1c (patch) | |
tree | 6db9b657c7935864f9a77d500d0b7dfa3b8e02fe | |
parent | b01652073d38e223f6569cb254b773593cc28f51 (diff) | |
parent | 89354a04f75ef22117dffcd0e32a89b0d352b9a1 (diff) | |
download | qcom-msm8x09-v3.10-d14e4d704776cca45d5675c3a86d356370760d1c.tar.gz |
Snap for 4911710 from 89354a04f75ef22117dffcd0e32a89b0d352b9a1 to nyc-iot-release
Change-Id: I2347790546f48874df8f54f4d635ac2be4d5f13b
42 files changed, 1705 insertions, 1143 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 593485b02ee..e05e8e9a2fe 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -82,6 +82,14 @@ config ARM_ARCH_TIMER_EVTSTREAM This must be disabled for hardware validation purposes to detect any hardware anomalies of missing events. +config ARM_ARCH_TIMER_VCT_ACCESS + bool "Support for ARM architected timer virtual counter access in userspace" + default !ARM64 + depends on ARM_ARCH_TIMER + help + This option enables support for reading the ARM architected timer's + virtual counter in userspace. + config CLKSRC_METAG_GENERIC def_bool y if METAG help diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 1bdf38aab48..5cc40f84170 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -319,8 +319,14 @@ static void arch_counter_set_user_access(void) | ARCH_TIMER_VIRT_EVT_EN | ARCH_TIMER_USR_PCT_ACCESS_EN); + /* Enable user access to the physical counter */ + cntkctl |= ARCH_TIMER_USR_PCT_ACCESS_EN; + /* Enable user access to the virtual counter */ - cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; + if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS)) + cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; + else + cntkctl &= ~ARCH_TIMER_USR_VCT_ACCESS_EN; arch_timer_set_cntkctl(cntkctl); } diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ada164e1b3a..60d77af9e02 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1016,6 +1016,8 @@ static int usbhid_parse(struct hid_device *hid) unsigned int rsize = 0; char *rdesc; int ret, n; + int num_descriptors; + size_t offset = offsetof(struct hid_descriptor, desc); quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); @@ -1038,10 +1040,18 @@ static int usbhid_parse(struct hid_device *hid) return -ENODEV; } + if (hdesc->bLength < sizeof(struct hid_descriptor)) { + dbg_hid("hid descriptor is too short\n"); + return -EINVAL; + } + hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - for (n = 0; n < hdesc->bNumDescriptors; n++) + num_descriptors = min_t(int, hdesc->bNumDescriptors, + (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor)); + + for (n = 0; n < num_descriptors; n++) if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c index e08a869a65b..0ebe62348d9 100644 --- a/drivers/platform/msm/ipa/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_rt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014,2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1072,6 +1072,15 @@ int __ipa_del_rt_rule(u32 rule_hdl) return -EINVAL; } + if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) { + IPADBG("Deleting rule from default rt table idx=%u\n", + entry->tbl->idx); + if (entry->tbl->rule_cnt == 1) { + IPAERR("Default tbl last rule cannot be deleted\n"); + return -EINVAL; + } + } + if (entry->hdr) __ipa_release_hdr(entry->hdr->id); else if (entry->proc_ctx) diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c index a51eb75b79e..29fc139bde2 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2014, 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2014, 2016-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -490,6 +490,12 @@ ol_rx_defrag_waitlist_flush( } tid = rx_reorder->tid; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", __func__, tid); + WARN_ON(1); + continue; + } /* get index 0 of the rx_reorder array */ rx_reorder_base = rx_reorder - tid; peer = container_of(rx_reorder_base, struct ol_txrx_peer_t, tids_rx_reorder[0]); diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c index c7bffde0e46..0e9928a332b 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -556,6 +556,13 @@ ol_rx_addba_handler( struct ol_txrx_peer_t *peer; struct ol_rx_reorder_t *rx_reorder; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", __func__, tid); + WARN_ON(1); + return; + } + peer = ol_txrx_peer_find_by_id(pdev, peer_id); if (peer == NULL) { return; @@ -596,6 +603,13 @@ ol_rx_delba_handler( struct ol_txrx_peer_t *peer; struct ol_rx_reorder_t *rx_reorder; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", __func__, tid); + WARN_ON(1); + return; + } + peer = ol_txrx_peer_find_by_id(pdev, peer_id); if (peer == NULL) { return; @@ -705,6 +719,13 @@ ol_rx_pn_ind_handler( u_int16_t seq_num; int i=0; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid tid, %u\n", __func__, tid); + WARN_ON(1); + return; + } + peer = ol_txrx_peer_find_by_id(pdev, peer_id); if (!peer) { diff --git a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx_send.c b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx_send.c index dd5cff498af..bc6120b6749 100644 --- a/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx_send.c +++ b/drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx_send.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -710,7 +710,14 @@ ol_tx_completion_handler( trace_str = (status) ? "OT:C:F:" : "OT:C:S:"; for (i = 0; i < num_msdus; i++) { tx_desc_id = desc_ids[i]; + if (tx_desc_id >= pdev->tx_desc.pool_size) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: drop due to invalid msdu id = %x\n", + __func__, tx_desc_id); + continue; + } tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + adf_os_assert(tx_desc); tx_desc->status = status; netbuf = tx_desc->netbuf; @@ -991,7 +998,14 @@ ol_tx_inspect_handler( for (i = 0; i < num_msdus; i++) { tx_desc_id = desc_ids[i]; + if (tx_desc_id >= pdev->tx_desc.pool_size) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: drop due to invalid msdu id = %x\n", + __func__, tx_desc_id); + continue; + } tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + adf_os_assert(tx_desc); netbuf = tx_desc->netbuf; /* find the "vdev" this tx_desc belongs to */ diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_main.h b/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_main.h index 2f9e90e8c76..ebc56c1afef 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_main.h +++ b/drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_main.h @@ -342,26 +342,11 @@ struct linkspeedContext unsigned int magic; }; -/** - * struct random_mac_context - Context used with hdd_random_mac_callback - * @random_mac_completion: Event on which hdd_set_random_mac will wait - * @adapter: Pointer to adapter - * @magic: For valid context this is set to ACTION_FRAME_RANDOM_CONTEXT_MAGIC - * @set_random_addr: Status of random filter set - */ -struct random_mac_context { - struct completion random_mac_completion; - hdd_adapter_t *adapter; - unsigned int magic; - bool set_random_addr; -}; - extern spinlock_t hdd_context_lock; #define STATS_CONTEXT_MAGIC 0x53544154 //STAT #define PEER_INFO_CONTEXT_MAGIC 0x52535349 /* PEER_INFO */ #define POWER_CONTEXT_MAGIC 0x504F5752 //POWR -#define SNR_CONTEXT_MAGIC 0x534E5200 //SNR #define LINK_CONTEXT_MAGIC 0x4C494E4B //LINKSPEED #define LINK_STATUS_MAGIC 0x4C4B5354 //LINKSTATUS(LNST) #define TEMP_CONTEXT_MAGIC 0x74656d70 // TEMP (temperature) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c index ef2ec7c507a..05df4f3c362 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -81,6 +81,7 @@ #include "wlan_hdd_main.h" #include "wlan_hdd_assoc.h" #include "wlan_hdd_power.h" +#include "wlan_hdd_request_manager.h" #include "wlan_hdd_trace.h" #include "vos_types.h" #include "vos_trace.h" @@ -25353,6 +25354,10 @@ static void wlan_hdd_fill_rate_info(hdd_ap_ctx_t *ap_ctx, flags); } +struct peer_info_priv { + struct sir_peer_info_ext peer_info_ext; +}; + /** * wlan_hdd_get_peer_info_cb() - get peer info callback * @sta_info: pointer of peer information @@ -25362,72 +25367,37 @@ static void wlan_hdd_fill_rate_info(hdd_ap_ctx_t *ap_ctx, * */ void wlan_hdd_get_peer_info_cb(struct sir_peer_info_ext_resp *sta_info, - void *context) + void *context) { - struct statsContext *get_peer_info_context; - struct sir_peer_info_ext *peer_info; - hdd_adapter_t *adapter; - hdd_ap_ctx_t *ap_ctx; + struct hdd_request *request; + struct peer_info_priv *priv; - if ((NULL == sta_info) || (NULL == context)) { + if (NULL == sta_info) { hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Bad param, sta_info [%pK] context [%pK]", - __func__, sta_info, context); - return; - } - - spin_lock(&hdd_context_lock); - /* - * there is a race condition that exists between this callback - * function and the caller since the caller could time out either - * before or while this code is executing. we use a spinlock to - * serialize these actions - */ - get_peer_info_context = context; - if (PEER_INFO_CONTEXT_MAGIC != - get_peer_info_context->magic) { - /* - * the caller presumably timed out so there is nothing - * we can do - */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, magic [%08x]", - __func__, - get_peer_info_context->magic); + "%s: Bad param, sta_info [%pK]", __func__, sta_info); return; } if (!sta_info->count) { - spin_unlock(&hdd_context_lock); hddLog(VOS_TRACE_LEVEL_ERROR, - FL("Fail to get remote peer info")); + FL("Fail to get remote peer info")); return; } - adapter = get_peer_info_context->pAdapter; - ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); - vos_mem_zero(&ap_ctx->txrx_stats, - sizeof(struct hdd_fw_txrx_stats)); - - peer_info = sta_info->info; - ap_ctx->txrx_stats.tx_packets = peer_info->tx_packets; - ap_ctx->txrx_stats.tx_bytes = peer_info->tx_bytes; - ap_ctx->txrx_stats.rx_packets = peer_info->rx_packets; - ap_ctx->txrx_stats.rx_bytes = peer_info->rx_bytes; - ap_ctx->txrx_stats.tx_retries = peer_info->tx_retries; - ap_ctx->txrx_stats.tx_failed = peer_info->tx_failed; - ap_ctx->txrx_stats.rssi = - peer_info->rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM; - wlan_hdd_fill_rate_info(ap_ctx, peer_info); + request = hdd_request_get(context); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Obsolete request", __func__); + return; + } - get_peer_info_context->magic = 0; + priv = hdd_request_priv(request); - /* notify the caller */ - complete(&get_peer_info_context->completion); + vos_mem_copy(&priv->peer_info_ext, + sta_info->info, + sizeof(sta_info->info[0])); - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + hdd_request_complete(request); + hdd_request_put(request); } /** @@ -25440,12 +25410,19 @@ void wlan_hdd_get_peer_info_cb(struct sir_peer_info_ext_resp *sta_info, * Return: 0 on success, otherwise error value */ static int wlan_hdd_get_peer_info(hdd_adapter_t *adapter, - v_MACADDR_t macaddress) + v_MACADDR_t macaddress) { eHalStatus hstatus; int ret; - struct statsContext context; + void *cookie; + hdd_ap_ctx_t *ap_ctx; struct sir_peer_info_ext_req peer_info_req; + struct hdd_request *request; + struct peer_info_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; if (NULL == adapter) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", @@ -25453,49 +25430,63 @@ static int wlan_hdd_get_peer_info(hdd_adapter_t *adapter, return -EFAULT; } - init_completion(&context.completion); - context.magic = PEER_INFO_CONTEXT_MAGIC; - context.pAdapter = adapter; + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Request allocation failure", + __func__); + return -ENOMEM; + } + + cookie = hdd_request_cookie(request); + priv = hdd_request_priv(request); vos_mem_copy(&(peer_info_req.peer_macaddr), &macaddress, VOS_MAC_ADDR_SIZE); peer_info_req.sessionid = adapter->sessionId; peer_info_req.reset_after_request = 0; hstatus = sme_get_peer_info_ext(WLAN_HDD_GET_HAL_CTX(adapter), - &peer_info_req, - &context, - wlan_hdd_get_peer_info_cb); + &peer_info_req, + cookie, + wlan_hdd_get_peer_info_cb); if (eHAL_STATUS_SUCCESS != hstatus) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Unable to retrieve statistics for peer info", __func__); ret = -EFAULT; } else { - if (!wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS))) { + ret = hdd_request_wait_for_response(request); + if (ret) { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: SME timed out while retrieving peer info", __func__); ret = -EFAULT; - } else + } else { + /* only support one peer by now */ + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + vos_mem_zero(&ap_ctx->txrx_stats, + sizeof(struct hdd_fw_txrx_stats)); + + ap_ctx->txrx_stats.tx_packets = + priv->peer_info_ext.tx_packets; + ap_ctx->txrx_stats.tx_bytes = + priv->peer_info_ext.tx_bytes; + ap_ctx->txrx_stats.rx_packets = + priv->peer_info_ext.rx_packets; + ap_ctx->txrx_stats.rx_bytes = + priv->peer_info_ext.rx_bytes; + ap_ctx->txrx_stats.tx_retries = + priv->peer_info_ext.tx_retries; + ap_ctx->txrx_stats.tx_failed = + priv->peer_info_ext.tx_failed; + ap_ctx->txrx_stats.rssi = priv->peer_info_ext.rssi + + WLAN_HDD_TGT_NOISE_FLOOR_DBM; + wlan_hdd_fill_rate_info(ap_ctx, &priv->peer_info_ext); ret = 0; + } } - /* - * either we never sent a request, we sent a request and received a - * response or we sent a request and timed out. if we never sent a - * request or if we sent a request and got a response, we want to - * clear the magic out of paranoia. if we timed out there is a - * race condition such that the callback function could be - * executing at the same time we are. of primary concern is if the - * callback function had already verified the "magic" but had not - * yet set the completion variable when a timeout occurred. we - * serialize these activities by invalidating the magic while - * holding a shared spinlock which will cause us to block if the - * callback is currently executing - */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + + hdd_request_put(request); + return ret; } diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_hostapd.c index aa1b1c4dec0..f925c244351 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_hostapd.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_hostapd.c @@ -96,6 +96,7 @@ extern int process_wma_set_command(int sessid, int paramid, #include <wlan_hdd_wowl.h> #include "wlan_hdd_tsf.h" #include "wlan_hdd_oemdata.h" +#include "wlan_hdd_request_manager.h" #define IS_UP(_dev) \ (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP)) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c index 75b872b28a8..5a4160e0105 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c @@ -76,6 +76,7 @@ #include <wlan_hdd_wowl.h> #include <wlan_hdd_misc.h> #include <wlan_hdd_wext.h> +#include "wlan_hdd_request_manager.h" #include "wlan_hdd_trace.h" #include "vos_types.h" #include "vos_trace.h" @@ -4087,87 +4088,33 @@ void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) return; } -static void hdd_GetLink_statusCB(v_U8_t status, void *pContext) -{ - struct statsContext *pLinkContext; - hdd_adapter_t *pAdapter; - - if (NULL == pContext) { - hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Bad pContext [%pK]", - __func__, pContext); - return; - } - - pLinkContext = pContext; - pAdapter = pLinkContext->pAdapter; - - spin_lock(&hdd_context_lock); - - if ((NULL == pAdapter) || (LINK_STATUS_MAGIC != pLinkContext->magic)) { - /* the caller presumably timed out so there is nothing we can do */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, pAdapter [%pK] magic [%08x]", - __func__, pAdapter, pLinkContext->magic); - return; - } - - /* context is valid so caller is still waiting */ - - /* paranoia: invalidate the magic */ - pLinkContext->magic = 0; - - /* copy over the status */ - pAdapter->linkStatus = status; - - /* notify the caller */ - complete(&pLinkContext->completion); - - /* serialization is complete */ - spin_unlock(&hdd_context_lock); -} +struct fw_state { + bool fw_active; +}; /** * hdd_get_fw_state_cb() - validates the context and notifies the caller - * @callback_context: caller context + * @cookie: cookie from the request contest * * Return: none */ -static void hdd_get_fw_state_cb(void *callback_context) +static void hdd_get_fw_state_cb(void *cookie) { - struct statsContext *context; - hdd_adapter_t *adapter; + struct hdd_request *request; + struct fw_state *priv; - if (NULL == callback_context) { - hddLog(LOGE, FL("Bad pContext [%pK]"), callback_context); + request = hdd_request_get(cookie); + if (!request) { + hddLog(LOGE, FL("Obsolete request")); return; } - context = callback_context; - adapter = context->pAdapter; + priv = hdd_request_priv(request); - spin_lock(&hdd_context_lock); + priv->fw_active = true; - if ((NULL == adapter) || (FW_STATUS_MAGIC != context->magic)) { - /* the caller presumably timed out so there is - * nothing we can do - */ - spin_unlock(&hdd_context_lock); - hddLog(LOGE, FL("Invalid context, Adapter [%pK] magic [%08x]"), - adapter, context->magic); - return; - } - - /* context is valid so caller is still waiting */ - - /* paranoia: invalidate the magic */ - context->magic = 0; - - /* notify the caller */ - complete(&context->completion); - - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + hdd_request_complete(request); + hdd_request_put(request); } /** @@ -4184,42 +4131,73 @@ static void hdd_get_fw_state_cb(void *callback_context) bool wlan_hdd_get_fw_state(hdd_adapter_t *adapter) { hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); - struct statsContext context; - eHalStatus hstatus = eHAL_STATUS_SUCCESS; - unsigned long rc; - bool fw_active = true; + eHalStatus hstatus; + int ret; + void *cookie; + struct fw_state *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS, + }; + struct hdd_request *request; + bool fw_active; if (wlan_hdd_validate_context(hdd_ctx) != 0) return false; - init_completion(&context.completion); - context.pAdapter = adapter; - context.magic = FW_STATUS_MAGIC; + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(LOGE, FL("Request allocation failure")); + return false; + } + + cookie = hdd_request_cookie(request); + hstatus = sme_get_fw_state(WLAN_HDD_GET_HAL_CTX(adapter), hdd_get_fw_state_cb, - &context); - + cookie); if (eHAL_STATUS_SUCCESS != hstatus) { hddLog(LOGE, FL("Unable to retrieve firmware status")); fw_active = false; } else { /* request is sent -- wait for the response */ - rc = wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS)); - if (!rc) { + ret = hdd_request_wait_for_response(request); + if (ret) { hddLog(LOGE, FL("SME timed out while retrieving firmware status")); fw_active = false; + } else { + priv = hdd_request_priv(request); + fw_active = priv->fw_active; } } - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + hdd_request_put(request); return fw_active; } +struct link_status_priv { + uint8_t link_status; +}; + +static void hdd_get_link_status_cb(uint8_t status, void *context) +{ + struct hdd_request *request; + struct link_status_priv *priv; + + request = hdd_request_get(context); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Obsolete request", __func__); + return; + } + + priv = hdd_request_priv(request); + priv->link_status = status; + hdd_request_complete(request); + hdd_request_put(request); +} + /** * wlan_hdd_get_link_status() - get link status * @pAdapter: pointer to the adapter @@ -4234,50 +4212,68 @@ bool wlan_hdd_get_fw_state(hdd_adapter_t *adapter) */ static int wlan_hdd_get_link_status(hdd_adapter_t *pAdapter) { - hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - struct statsContext context; - eHalStatus hstatus; - unsigned long rc; - - if (pHddCtx->isLogpInProgress) { - hddLog(LOGW, FL("LOGP in Progress. Ignore!!!")); - return 0; - } + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + eHalStatus hstatus; + int ret; + void *cookie; + struct hdd_request *request; + struct link_status_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS, + }; + + if (pHddCtx->isLogpInProgress) { + hddLog(LOGW, FL("LOGP in Progress. Ignore!!!")); + return 0; + } - if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { - /* If not associated, then expected link status return value is 0 */ - hddLog(LOG1, FL("Not associated!")); - return 0; - } + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + /* If not associated, then expected link status return value is 0 */ + hddLog(LOG1, FL("Not associated!")); + return 0; + } - init_completion(&context.completion); - context.pAdapter = pAdapter; - context.magic = LINK_STATUS_MAGIC; - hstatus = sme_getLinkStatus(WLAN_HDD_GET_HAL_CTX(pAdapter), - hdd_GetLink_statusCB, - &context, - pAdapter->sessionId); - if (eHAL_STATUS_SUCCESS != hstatus) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Unable to retrieve link status", __func__); - /* return a cached value */ - } else { - /* request is sent -- wait for the response */ - rc = wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_LINK_STATUS)); - if (!rc) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while retrieving link status")); - } - } + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Request allocation failure", + __func__); + return 0; + } + cookie = hdd_request_cookie(request); - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + hstatus = sme_getLinkStatus(WLAN_HDD_GET_HAL_CTX(pAdapter), + hdd_get_link_status_cb, + cookie, + pAdapter->sessionId); + if (eHAL_STATUS_SUCCESS != hstatus) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve link status", __func__); + /* return a cached value */ + } else { + /* request is sent -- wait for the response */ + ret = hdd_request_wait_for_response(request); + if (ret) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: SME timed out while retrieving link status", + __func__); + /* return a cached value */ + } else { + /* update the adapter with the fresh results */ + priv = hdd_request_priv(request); + pAdapter->linkStatus = priv->link_status; + } + } + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + hdd_request_put(request); - /* either callback updated pAdapter stats or it has cached data */ - return pAdapter->linkStatus; + /* either callback updated adapter stats or it has cached data */ + return pAdapter->linkStatus; } #ifdef WLAN_FEATURE_ROAM_OFFLOAD @@ -4749,135 +4745,90 @@ static VOS_STATUS hdd_parse_ese_beacon_req(tANI_U8 *pValue, return VOS_STATUS_SUCCESS; } -static void hdd_GetTsmStatsCB( tAniTrafStrmMetrics tsmMetrics, - const tANI_U32 staId, - void *pContext ) -{ - struct statsContext *pStatsContext = NULL; - hdd_adapter_t *pAdapter = NULL; - - if (NULL == pContext) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Bad param, pContext [%pK]", - __func__, pContext); - return; - } - - /* there is a race condition that exists between this callback - function and the caller since the caller could time out either - before or while this code is executing. we use a spinlock to - serialize these actions */ - spin_lock(&hdd_context_lock); +struct tsm_priv { + tAniTrafStrmMetrics tsm_metrics; +}; - pStatsContext = pContext; - pAdapter = pStatsContext->pAdapter; - if ((NULL == pAdapter) || (STATS_CONTEXT_MAGIC != pStatsContext->magic)) { - /* the caller presumably timed out so there is nothing we can do */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, pAdapter [%pK] magic [%08x]", - __func__, pAdapter, pStatsContext->magic); - return; - } +static void hdd_GetTsmStatsCB(tAniTrafStrmMetrics tsmMetrics, + const tANI_U32 staId, + void *pContext) +{ + struct hdd_request *request; + struct tsm_priv *priv; - /* context is valid so caller is still waiting */ + ENTER(); + request = hdd_request_get(pContext); + if (!request) { + hddLog(LOGE, FL("Obsolete request")); + return; + } + priv = hdd_request_priv(request); + priv->tsm_metrics = tsmMetrics; + hdd_request_complete(request); + hdd_request_put(request); + EXIT(); +} - /* paranoia: invalidate the magic */ - pStatsContext->magic = 0; - - /* copy over the tsm stats */ - pAdapter->tsmStats.UplinkPktQueueDly = tsmMetrics.UplinkPktQueueDly; - vos_mem_copy(pAdapter->tsmStats.UplinkPktQueueDlyHist, - tsmMetrics.UplinkPktQueueDlyHist, - sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist)/ - sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist[0])); - pAdapter->tsmStats.UplinkPktTxDly = tsmMetrics.UplinkPktTxDly; - pAdapter->tsmStats.UplinkPktLoss = tsmMetrics.UplinkPktLoss; - pAdapter->tsmStats.UplinkPktCount = tsmMetrics.UplinkPktCount; - pAdapter->tsmStats.RoamingCount = tsmMetrics.RoamingCount; - pAdapter->tsmStats.RoamingDly = tsmMetrics.RoamingDly; +static VOS_STATUS hdd_get_tsm_stats(hdd_adapter_t *pAdapter, + const tANI_U8 tid, + tAniTrafStrmMetrics* pTsmMetrics) +{ + hdd_station_ctx_t *pHddStaCtx = NULL; + eHalStatus hstatus; + VOS_STATUS vstatus = VOS_STATUS_SUCCESS; + int ret; + hdd_context_t *pHddCtx = NULL; + void *cookie; + struct hdd_request *request; + struct tsm_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (!pAdapter) { + hddLog(LOGE, FL("pAdapter is NULL")); + return VOS_STATUS_E_FAULT; + } - /* notify the caller */ - complete(&pStatsContext->completion); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - /* serialization is complete */ - spin_unlock(&hdd_context_lock); -} + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(LOGE, FL("Request allocation failure")); + return VOS_STATUS_E_NOMEM; + } + cookie = hdd_request_cookie(request); -static VOS_STATUS hdd_get_tsm_stats(hdd_adapter_t *pAdapter, - const tANI_U8 tid, - tAniTrafStrmMetrics* pTsmMetrics) -{ - hdd_station_ctx_t *pHddStaCtx = NULL; - eHalStatus hstatus; - VOS_STATUS vstatus = VOS_STATUS_SUCCESS; - unsigned long rc; - struct statsContext context; - hdd_context_t *pHddCtx = NULL; - - if (NULL == pAdapter) { - hddLog(LOGE, FL("pAdapter is NULL")); - return VOS_STATUS_E_FAULT; - } + /* query tsm stats */ + hstatus = sme_GetTsmStats(pHddCtx->hHal, hdd_GetTsmStatsCB, + pHddStaCtx->conn_info.staId[ 0 ], + pHddStaCtx->conn_info.bssId, + cookie, pHddCtx->pvosContext, tid); + if (eHAL_STATUS_SUCCESS != hstatus) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve tsm statistics", + __func__); + vstatus = VOS_STATUS_E_FAULT; + goto cleanup; + } - pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + ret = hdd_request_wait_for_response(request); + if (ret) { + hddLog(LOGE, + FL("SME timed out while retrieving tsm statistics")); + vstatus = VOS_STATUS_E_TIMEOUT; + goto cleanup; + } - /* we are connected prepare our callback context */ - init_completion(&context.completion); - context.pAdapter = pAdapter; - context.magic = STATS_CONTEXT_MAGIC; - - /* query tsm stats */ - hstatus = sme_GetTsmStats(pHddCtx->hHal, hdd_GetTsmStatsCB, - pHddStaCtx->conn_info.staId[ 0 ], - pHddStaCtx->conn_info.bssId, - &context, pHddCtx->pvosContext, tid); - if (eHAL_STATUS_SUCCESS != hstatus) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Unable to retrieve statistics", - __func__); - vstatus = VOS_STATUS_E_FAULT; - } else { - /* request was sent -- wait for the response */ - rc = wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); - if (!rc) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: SME timed out while retrieving statistics", - __func__); - vstatus = VOS_STATUS_E_TIMEOUT; - } - } + priv = hdd_request_priv(request); + *pTsmMetrics = priv->tsm_metrics; - /* either we never sent a request, we sent a request and received a - response or we sent a request and timed out. if we never sent a - request or if we sent a request and got a response, we want to - clear the magic out of paranoia. if we timed out there is a - race condition such that the callback function could be - executing at the same time we are. of primary concern is if the - callback function had already verified the "magic" but had not - yet set the completion variable when a timeout occurred. we - serialize these activities by invalidating the magic while - holding a shared spinlock which will cause us to block if the - callback is currently executing */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); +cleanup: + hdd_request_put(request); - if (VOS_STATUS_SUCCESS == vstatus) { - pTsmMetrics->UplinkPktQueueDly = pAdapter->tsmStats.UplinkPktQueueDly; - vos_mem_copy(pTsmMetrics->UplinkPktQueueDlyHist, - pAdapter->tsmStats.UplinkPktQueueDlyHist, - sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist)/ - sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist[0])); - pTsmMetrics->UplinkPktTxDly = pAdapter->tsmStats.UplinkPktTxDly; - pTsmMetrics->UplinkPktLoss = pAdapter->tsmStats.UplinkPktLoss; - pTsmMetrics->UplinkPktCount = pAdapter->tsmStats.UplinkPktCount; - pTsmMetrics->RoamingCount = pAdapter->tsmStats.RoamingCount; - pTsmMetrics->RoamingDly = pAdapter->tsmStats.RoamingDly; - } - return vstatus; + return vstatus; } /** @@ -14754,6 +14705,8 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx) TRACK_UNLOAD_STATUS(unload_deinit_greep_ap); hdd_wlan_green_ap_deinit(pHddCtx); + hdd_request_manager_deinit(); + //Close Watchdog if (pConfig && pConfig->fIsLogpEnabled) vos_watchdog_close(pVosContext); @@ -16639,6 +16592,7 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc) goto err_wdclose; } + hdd_request_manager_init(); hdd_wlan_green_ap_init(pHddCtx); status = vos_open( &pVosContext, 0); @@ -17498,6 +17452,7 @@ err_vos_nv_close: vos_nv_close(); hdd_wlan_green_ap_deinit(pHddCtx); + hdd_request_manager_deinit(); err_wdclose: if(pHddCtx->cfg_ini->fIsLogpEnabled) diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c index 363d1a1076c..dafdaf5eced 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c @@ -51,6 +51,7 @@ #include "vos_types.h" #include "vos_trace.h" #include "vos_sched.h" +#include "wlan_hdd_request_manager.h" //Ms to Micro Sec #define MS_TO_MUS(x) ((x)*1000) @@ -165,6 +166,10 @@ static bool hdd_p2p_is_action_type_rsp( const u8 *buf, uint32_t len ) return FALSE; } +struct random_mac_priv { + bool set_random_addr; +}; + /** * hdd_random_mac_callback() - Callback invoked from wmi layer * @set_random_addr: Status of random mac filter set operation @@ -177,32 +182,20 @@ static bool hdd_p2p_is_action_type_rsp( const u8 *buf, uint32_t len ) */ static void hdd_random_mac_callback(bool set_random_addr, void *context) { - struct random_mac_context *rnd_ctx; - hdd_adapter_t *adapter; - - if (!context) { - hddLog(LOGE, FL("Bad param, pContext")); - return; - } - - rnd_ctx = context; - adapter = rnd_ctx->adapter; + struct hdd_request *request; + struct random_mac_priv *priv; - spin_lock(&hdd_context_lock); - if ((!adapter) || - (rnd_ctx->magic != ACTION_FRAME_RANDOM_CONTEXT_MAGIC)) { - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - FL("Invalid context, magic [%08x]"), rnd_ctx->magic); + request = hdd_request_get(context); + if (!request) { + hddLog(LOGE,FL("invalid request")); return; } - rnd_ctx->magic = 0; - if (set_random_addr) - rnd_ctx->set_random_addr = true; + priv = hdd_request_priv(request); + priv->set_random_addr = set_random_addr; - complete(&rnd_ctx->random_mac_completion); - spin_unlock(&hdd_context_lock); + hdd_request_complete(request); + hdd_request_put(request); } /** @@ -214,11 +207,17 @@ static void hdd_random_mac_callback(bool set_random_addr, void *context) */ static bool hdd_set_random_mac(hdd_adapter_t *adapter, uint8_t *random_mac_addr) { - struct random_mac_context context; hdd_context_t *hdd_ctx; eHalStatus sme_status; unsigned long rc; + void *cookie; bool status = false; + struct hdd_request *request; + struct random_mac_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_SET_RND, + }; ENTER(); hdd_ctx = WLAN_HDD_GET_CTX(adapter); @@ -227,32 +226,33 @@ static bool hdd_set_random_mac(hdd_adapter_t *adapter, uint8_t *random_mac_addr) return false; } - init_completion(&context.random_mac_completion); - context.adapter = adapter; - context.magic = ACTION_FRAME_RANDOM_CONTEXT_MAGIC; - context.set_random_addr = false; + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(LOGE, FL("Request allocation failure")); + return false; + } + + cookie = hdd_request_cookie(request); sme_status = sme_set_random_mac(hdd_ctx->hHal, hdd_random_mac_callback, adapter->sessionId, random_mac_addr, - &context); + cookie); if (sme_status != eHAL_STATUS_SUCCESS) { hddLog(LOGE,FL("Unable to set random mac")); } else { - rc = wait_for_completion_timeout(&context.random_mac_completion, - msecs_to_jiffies(WLAN_WAIT_TIME_SET_RND)); - if (!rc) { - hddLog(LOGE, - FL("SME timed out while setting random mac")); + rc = hdd_request_wait_for_response(request); + if (rc) { + hddLog(LOGE, FL("SME timed out while setting random mac")); + } else { + priv = hdd_request_priv(request); + status = priv->set_random_addr; } } - spin_lock(&hdd_context_lock); - context.magic = 0; - status = context.set_random_addr; - spin_unlock(&hdd_context_lock); - + hdd_request_put(request); EXIT(); + return status; } diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.c new file mode 100644 index 00000000000..16a968995e0 --- /dev/null +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/kernel.h> +#include "wlan_hdd_request_manager.h" +#include "wlan_hdd_main.h" +#include "vos_list.h" +#include "vos_event.h" +#include "vos_memory.h" + +/* arbitrary value */ +#define MAX_NUM_REQUESTS 20 + +static bool is_initialized; +static hdd_list_t requests; +static adf_os_spinlock_t spinlock; +static void *cookie; + +struct hdd_request { + hdd_list_node_t node; + void *cookie; + uint32_t reference_count; + struct hdd_request_params params; + vos_event_t completed; +}; + +/* must be called with spinlock held */ +static void hdd_request_unlink(struct hdd_request *request) +{ + hdd_list_remove_node(&requests, &request->node); +} + +static void hdd_request_destroy(struct hdd_request *request) +{ + struct hdd_request_params *params; + + params = &request->params; + if (params->dealloc) { + void *priv = hdd_request_priv(request); + + params->dealloc(priv); + } + vos_event_destroy(&request->completed); + vos_mem_free(request); +} + +/* must be called with spinlock held */ +static struct hdd_request *hdd_request_find(void *cookie) +{ + VOS_STATUS status; + struct hdd_request *request; + hdd_list_node_t *node; + + status = hdd_list_peek_front(&requests, &node); + while (VOS_IS_STATUS_SUCCESS(status)) { + request = container_of(node, struct hdd_request, node); + if (request->cookie == cookie) + return request; + status = hdd_list_peek_next(&requests, node, &node); + } + + return NULL; +} + +struct hdd_request *hdd_request_alloc(const struct hdd_request_params *params) +{ + size_t length; + struct hdd_request *request; + + if (!is_initialized) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: invoked when not initialized from %pS", + __func__, (void *)_RET_IP_); + return NULL; + } + + length = sizeof(*request) + params->priv_size; + request = vos_mem_malloc(length); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: allocation failed for %pS", + __func__, (void *)_RET_IP_); + return NULL; + } + request->reference_count = 1; + request->params = *params; + vos_event_init(&request->completed); + adf_os_spin_lock_bh(&spinlock); + request->cookie = cookie++; + hdd_list_insert_back(&requests, &request->node); + adf_os_spin_unlock_bh(&spinlock); + hddLog(VOS_TRACE_LEVEL_DEBUG, + "%s: request %pK, cookie %pK, caller %pS", + __func__, request, request->cookie, (void *)_RET_IP_); + + return request; +} + +void *hdd_request_priv(struct hdd_request *request) +{ + /* private data area immediately follows the struct hdd_request */ + return request + 1; +} + +void *hdd_request_cookie(struct hdd_request *request) +{ + return request->cookie; +} + +struct hdd_request *hdd_request_get(void *cookie) +{ + struct hdd_request *request; + + if (!is_initialized) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: invoked when not initialized from %pS", + __func__, (void *)_RET_IP_); + return NULL; + } + adf_os_spin_lock_bh(&spinlock); + request = hdd_request_find(cookie); + if (request) + request->reference_count++; + adf_os_spin_unlock_bh(&spinlock); + hddLog(VOS_TRACE_LEVEL_DEBUG, + "%s: cookie %pK, request %pK, caller %pS", + __func__, cookie, request, (void *)_RET_IP_); + + return request; +} + +void hdd_request_put(struct hdd_request *request) +{ + bool unlinked = false; + + hddLog(VOS_TRACE_LEVEL_DEBUG, + "%s: request %pK, cookie %pK, caller %pS", + __func__, request, request->cookie, (void *)_RET_IP_); + adf_os_spin_lock_bh(&spinlock); + request->reference_count--; + if (0 == request->reference_count) { + hdd_request_unlink(request); + unlinked = true; + } + adf_os_spin_unlock_bh(&spinlock); + if (unlinked) + hdd_request_destroy(request); +} + +int hdd_request_wait_for_response(struct hdd_request *request) +{ + VOS_STATUS status; + + status = vos_wait_single_event(&request->completed, + request->params.timeout_ms); + + return vos_status_to_os_return(status); +} + +void hdd_request_complete(struct hdd_request *request) +{ + (void) vos_event_set(&request->completed); +} + +void hdd_request_manager_init(void) +{ + hddLog(VOS_TRACE_LEVEL_DEBUG, "%s: %pS", __func__, (void *)_RET_IP_); + if (is_initialized) + return; + + hdd_list_init(&requests, MAX_NUM_REQUESTS); + adf_os_spinlock_init(&spinlock); + is_initialized = true; +} + +/* + * hdd_request_manager_deinit implementation note: + * It is intentional that we do not destroy the list or the spinlock. + * This allows threads to still access the infrastructure even when it + * has been deinitialized. Since neither lists nor spinlocks consume + * resources this does not result in a resource leak. + */ +void hdd_request_manager_deinit(void) +{ + hddLog(VOS_TRACE_LEVEL_DEBUG, "%s: %pS", __func__, (void *)_RET_IP_); + is_initialized = false; +} diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.h b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.h new file mode 100644 index 00000000000..357ef2a12d6 --- /dev/null +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_REQUEST_MANAGER_H__ +#define __WLAN_HDD_REQUEST_MANAGER_H__ + +/** + * DOC: WLAN HDD REQUEST MANAGER + * + * Many operations within the wlan driver occur in an asynchronous + * manner. Requests are received by HDD via one of the kernel + * interfaces (ioctl, nl80211, virtual file system, etc.). The + * requests are translated to an internal format and are then passed + * to lower layers, usually via SME, for processing. For requests + * which require a response, that response comes up from the lower + * layers in a separate thread of execution, ultimately resulting in a + * call to a callback function that was provided by HDD as part of the + * initial request. So a mechanism is needed to synchronize the + * request and response. This framework provides that mechanism. + * + * Once the framework has been initialized, the typical sequence of + * events is as follows: + * + * Request Thread: + * 1. Create a &struct hdd_request_params which describes the request. + * 2. Call hdd_request_alloc() to allocate a &struct hdd_request. + * 3. Call hdd_request_priv() to get a pointer to the private data. + * 4. Place any information which must be shared with the Response + * Callback in the private data area. + * 5. Call hdd_request_cookie() to get the unique cookie assigned + * to the request. + * 6. Call the underlying request handling API, passing the cookie + * as the callback's private context. + * 7. Call hdd_request_wait_for_response() to wait for the response + * (or for the request to time out). + * 8. Use the return status to see if the request was successful. If + * it was, retrieve any response information from the private + * structure and prepare a response for userspace. + * 9. Call hdd_request_put() to relinquish access to the request. + * 10. Return status to the caller. + * + * Response Callback: + * 1. Call hdd_request_get() with the provided cookie to see if the + * request structure is still valid. If it returns %NULL then + * return since this means the request thread has already timed + * out. + * 2. Call hdd_request_priv() to get access to the private data area. + * 3. Write response data into the private data area. + * 4. Call hdd_request_complete() to indicate that the response is + * ready to be processed by the request thread. + * 5. Call hdd_request_put() to relinquish the callback function's + * reference to the request. + */ + +/* this is opaque to clients */ +struct hdd_request; + +/** + * typedef hdd_request_dealloc - Private data deallocation function + */ +typedef void (*hdd_request_dealloc)(void *priv); + +/** + * struct hdd_request_params - HDD request parameters + * @priv_size: Size of the private data area required to pass + * information between the request thread and the response callback. + * @timeout_ms: The amount of time to wait for a response in milliseconds. + * @dealloc: Function to be called when the request is destroyed to + * deallocate any allocations made in the private area of the + * request struct. Can be %NULL if no private allocations are + * made. + */ +struct hdd_request_params { + uint32_t priv_size; + uint32_t timeout_ms; + hdd_request_dealloc dealloc; +}; + +/** + * hdd_request_alloc() - Allocate a request struct + * @params: parameter block that specifies the attributes of the + * request + * + * This function will attempt to allocate a &struct hdd_request with + * the specified @params. If successful, the caller can then use + * request struct to make an asynchronous request. Once the request is + * no longer needed, the reference should be relinquished via a call + * to hdd_request_put(). + * + * Return: A pointer to an allocated &struct hdd_request (which also + * contains room for the private buffer) if the allocation is + * successful, %NULL if the allocation fails. + */ +struct hdd_request *hdd_request_alloc(const struct hdd_request_params *params); + +/** + * hdd_request_priv() - Get pointer to request private data + * @request: The request struct that contains the private data + * + * This function will return a pointer to the private data area that + * is part of the request struct. The caller must already have a valid + * reference to @request from either hdd_request_alloc() or + * hdd_request_get(). + * + * Returns: pointer to the private data area. Note that this pointer + * will always be an offset from the input @request pointer and hence + * this function will never return %NULL. + */ +void *hdd_request_priv(struct hdd_request *request); + +/** + * hdd_request_cookie() - Get cookie of a request + * @request: The request struct associated with the request + * + * This function will return the unique cookie that has been assigned + * to the request. This cookie can subsequently be passed to + * hdd_request_get() to retrieve the request. + * + * Note that the cookie is defined as a void pointer as it is intended + * to be passed as an opaque context pointer from HDD to underlying + * layers when making a request, and subsequently passed back to HDD + * as an opaque pointer in an asynchronous callback. + * + * Returns: The cookie assigned to the request. + */ +void *hdd_request_cookie(struct hdd_request *request); + +/** + * hdd_request_get() - Get a reference to a request struct + * @cookie: The cookie of the request struct that needs to be + * referenced + * + * This function will use the cookie to determine if the associated + * request struct is valid, and if so, will increment the reference + * count of the struct. This means the caller is guaranteed that the + * request struct is valid and the underlying private data can be + * dereferenced. + * + * Returns: The pointer to the request struct associated with @cookie + * if the request is still valid, %NULL if the underlying request + * struct is no longer valid. + */ +struct hdd_request *hdd_request_get(void *cookie); + +/** + * hdd_request_put() - Release a reference to a request struct + * @request: The request struct that no longer needs to be referenced + * + * This function will decrement the reference count of the struct, and + * will clean up the request if this is the last reference. The caller + * must already have a valid reference to @request, either from + * hdd_request_alloc() or hdd_request_get(). + * + * Returns: Nothing + */ +void hdd_request_put(struct hdd_request *request); + +/** + * hdd_request_wait_for_response() - Wait for a response + * @request: The request struct associated with the request + * + * This function will wait until either a response is received and + * communicated via hdd_request_complete(), or until the request + * timeout period expires. + * + * Returns: 0 if a response was received, -ETIMEDOUT if the response + * timed out. + */ +int hdd_request_wait_for_response(struct hdd_request *request); + +/** + * hdd_request_complete() - Complete a request + * @request: The request struct associated with the request + * + * This function is used to indicate that a response has been received + * and that any information required by the request thread has been + * copied into the private data area of the request struct. This will + * unblock any hdd_request_wait_for_response() that is pending on this + * @request. + * + * Returns: Nothing + */ +void hdd_request_complete(struct hdd_request *request); + +/** + * hdd_request_manager_init() - Initialize the HDD Request Manager + * + * This function must be called during system initialization to + * initialize the HDD Request Manager. + * + * Returns: Nothing + */ +void hdd_request_manager_init(void); + +/** + * hdd_request_manager_deinit() - Deinitialize the HDD Request Manager + * + * This function must be called during system shutdown to deinitialize + * the HDD Request Manager. + * + * Returns: Nothing + */ +void hdd_request_manager_deinit(void); + +#endif /* __WLAN_HDD_REQUEST_MANAGER_H__ */ diff --git a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_wext.c b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_wext.c index 49708b9937e..877c23e9627 100644 --- a/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_wext.c +++ b/drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_wext.c @@ -111,6 +111,7 @@ #include "wlan_hdd_tsf.h" #include "vos_nvitem.h" #include "wlan_hdd_oemdata.h" +#include "wlan_hdd_request_manager.h" #define HDD_FINISH_ULA_TIME_OUT 800 #define HDD_SET_MCBC_FILTERS_TO_FW 1 @@ -1213,279 +1214,253 @@ hdd_IsAuthTypeRSN( tHalHandle halHandle, eCsrAuthType authType) return rsnType; } -static void hdd_GetRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext ) -{ - struct statsContext *pStatsContext; - hdd_adapter_t *pAdapter; - - if (ioctl_debug) - { - pr_info("%s: rssi [%d] STA [%d] pContext [%pK]\n", - __func__, (int)rssi, (int)staId, pContext); - } - - if (NULL == pContext) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Bad param, pContext [%pK]", - __func__, pContext); - return; - } - - pStatsContext = pContext; - pAdapter = pStatsContext->pAdapter; - - /* there is a race condition that exists between this callback - function and the caller since the caller could time out either - before or while this code is executing. we use a spinlock to - serialize these actions */ - spin_lock(&hdd_context_lock); - - if ((NULL == pAdapter) || (PEER_INFO_CONTEXT_MAGIC != pStatsContext->magic)) - { - /* the caller presumably timed out so there is nothing we can do */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, pAdapter [%pK] magic [%08x]", - __func__, pAdapter, pStatsContext->magic); - if (ioctl_debug) - { - pr_info("%s: Invalid context, pAdapter [%pK] magic [%08x]\n", - __func__, pAdapter, pStatsContext->magic); - } - return; - } - - /* context is valid so caller is still waiting */ +struct rssi_priv { + v_S7_t rssi; +}; - /* paranoia: invalidate the magic */ - pStatsContext->magic = 0; +/** + * hdd_get_rssi_cb() - "Get RSSI" callback function + * @rssi: Current RSSI of the station + * @sta_id: ID of the station + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * + * Return: None + */ +static void hdd_get_rssi_cb(v_S7_t rssi, tANI_U32 sta_id, void *context) +{ + struct hdd_request *request; + struct rssi_priv *priv; - /* copy over the rssi */ - pAdapter->rssi = rssi; + if (ioctl_debug) { + pr_info("%s: rssi [%d] sta_id [%d] context [%pK]\n", + __func__, (int)rssi, (int)sta_id, context); + } - if (pAdapter->rssi > 0) - pAdapter->rssi = 0; - /* notify the caller */ - complete(&pStatsContext->completion); + request = hdd_request_get(context); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Obsolete request", __func__); + return; + } - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + priv = hdd_request_priv(request); + priv->rssi = rssi; + hdd_request_complete(request); + hdd_request_put(request); } -static void hdd_GetSnrCB(tANI_S8 snr, tANI_U32 staId, void *pContext) +/** + * wlan_hdd_get_rssi() - Get the current RSSI + * @pAdapter: adapter upon which the measurement is requested + * @rssi_value: pointer to where the RSSI should be returned + * + * Return: VOS_STATUS_SUCCESS on success, VOS_STATUS_E_** on error + */ +VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value) { - struct statsContext *pStatsContext; - hdd_adapter_t *pAdapter; - - if (ioctl_debug) - { - pr_info("%s: snr [%d] STA [%d] pContext [%pK]\n", - __func__, (int)snr, (int)staId, pContext); - } - - if (NULL == pContext) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Bad param, pContext [%pK]", - __func__, pContext); - return; - } - - pStatsContext = pContext; - pAdapter = pStatsContext->pAdapter; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + eHalStatus hstatus; + int ret; + void *cookie; + struct hdd_request *request; + struct rssi_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (NULL == pAdapter) { + hddLog(VOS_TRACE_LEVEL_WARN, + "%s: Invalid context, pAdapter", __func__); + return VOS_STATUS_E_FAULT; + } + if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s:LOGP in Progress. Ignore!!!",__func__); + /* return a cached value */ + *rssi_value = pAdapter->rssi; + return VOS_STATUS_SUCCESS; + } - /* there is a race condition that exists between this callback - function and the caller since the caller could time out either - before or while this code is executing. we use a spinlock to - serialize these actions */ - spin_lock(&hdd_context_lock); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - if ((NULL == pAdapter) || (SNR_CONTEXT_MAGIC != pStatsContext->magic)) - { - /* the caller presumably timed out so there is nothing we can do */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, pAdapter [%pK] magic [%08x]", - __func__, pAdapter, pStatsContext->magic); - if (ioctl_debug) - { - pr_info("%s: Invalid context, pAdapter [%pK] magic [%08x]\n", - __func__, pAdapter, pStatsContext->magic); - } - return; - } + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hddLog(LOG1, "%s: Not associated, rssi on disconnect %d", + __func__, pAdapter->rssi_on_disconnect); + *rssi_value = pAdapter->rssi_on_disconnect; + return VOS_STATUS_SUCCESS; + } - /* context is valid so caller is still waiting */ + if (pHddStaCtx->hdd_ReassocScenario) { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, + "%s: Roaming in progress, return cached RSSI", + __func__); + *rssi_value = pAdapter->rssi; + return VOS_STATUS_SUCCESS; + } - /* paranoia: invalidate the magic */ - pStatsContext->magic = 0; + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Request allocation failure, return cached RSSI", + __func__); + *rssi_value = pAdapter->rssi; + return VOS_STATUS_SUCCESS; + } + cookie = hdd_request_cookie(request); + + hstatus = sme_GetRssi(pHddCtx->hHal, hdd_get_rssi_cb, + pHddStaCtx->conn_info.staId[0], + pHddStaCtx->conn_info.bssId, pAdapter->rssi, + cookie, pHddCtx->pvosContext); + if (eHAL_STATUS_SUCCESS != hstatus) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Unable to retrieve RSSI", + __func__); + /* we'll returned a cached value below */ + } else { + /* request was sent -- wait for the response */ + ret = hdd_request_wait_for_response(request); + if (ret) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving RSSI")); + /* we'll returned a cached value below */ + } else { + /* update the adapter with the fresh results */ + priv = hdd_request_priv(request); + pAdapter->rssi = priv->rssi; + if (pAdapter->rssi > 0) + pAdapter->rssi = 0; + } + } - /* copy over the snr */ - pAdapter->snr = snr; + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + hdd_request_put(request); - /* notify the caller */ - complete(&pStatsContext->completion); + *rssi_value = pAdapter->rssi; - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + return VOS_STATUS_SUCCESS; } -VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value) -{ - struct statsContext context; - hdd_context_t *pHddCtx; - hdd_station_ctx_t *pHddStaCtx; - eHalStatus hstatus; - unsigned long rc; - - if (NULL == pAdapter) - { - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, pAdapter", __func__); - return VOS_STATUS_E_FAULT; - } - if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:LOGP in Progress. Ignore!!!",__func__); - /* return a cached value */ - *rssi_value = pAdapter->rssi; - return VOS_STATUS_SUCCESS; - } - - pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - - if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { - hddLog(LOG1, "%s: Not associated, rssi on disconnect %d", - __func__, pAdapter->rssi_on_disconnect); - *rssi_value = pAdapter->rssi_on_disconnect; - return VOS_STATUS_SUCCESS; - } - - if (VOS_TRUE == pHddStaCtx->hdd_ReassocScenario) - { - VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, - "%s: Roaming in progress, return cached RSSI", __func__); - *rssi_value = pAdapter->rssi; - return VOS_STATUS_SUCCESS; - } - - init_completion(&context.completion); - context.pAdapter = pAdapter; - context.magic = PEER_INFO_CONTEXT_MAGIC; +struct snr_priv { + tANI_S8 snr; +}; - hstatus = sme_GetRssi(pHddCtx->hHal, hdd_GetRssiCB, - pHddStaCtx->conn_info.staId[ 0 ], - pHddStaCtx->conn_info.bssId, pAdapter->rssi, - &context, pHddCtx->pvosContext); - if (eHAL_STATUS_SUCCESS != hstatus) - { - hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Unable to retrieve RSSI", - __func__); - /* we'll returned a cached value below */ - } - else - { - /* request was sent -- wait for the response */ - rc = wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); - if (!rc) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while retrieving RSSI")); - /* we'll now returned a cached value below */ - } - } +/** + * hdd_get_snr_cb() - "Get SNR" callback function + * @snr: Current SNR of the station + * @sta_id: ID of the station + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * + * Return: None + */ +static void hdd_get_snr_cb(tANI_S8 snr, tANI_U32 sta_id, void *context) +{ + struct hdd_request *request; + struct snr_priv *priv; - /* either we never sent a request, we sent a request and received a - response or we sent a request and timed out. if we never sent a - request or if we sent a request and got a response, we want to - clear the magic out of paranoia. if we timed out there is a - race condition such that the callback function could be - executing at the same time we are. of primary concern is if the - callback function had already verified the "magic" but had not - yet set the completion variable when a timeout occurred. we - serialize these activities by invalidating the magic while - holding a shared spinlock which will cause us to block if the - callback is currently executing */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + if (ioctl_debug) { + pr_info("%s: snr [%d] sta_id [%d] context [%pK]\n", + __func__, (int)snr, (int)sta_id, context); + } - *rssi_value = pAdapter->rssi; - hddLog(LOG1, FL("RSSI = %d"), *rssi_value); + request = hdd_request_get(context); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Obsolete request", __func__); + return; + } - return VOS_STATUS_SUCCESS; + /* propagate response back to requesting thread */ + priv = hdd_request_priv(request); + priv->snr = snr; + hdd_request_complete(request); + hdd_request_put(request); } +/** + * wlan_hdd_get_snr() - Get the current SNR + * @pAdapter: adapter upon which the measurement is requested + * @snr: pointer to where the SNR should be returned + * + * Return: VOS_STATUS_SUCCESS on success, VOS_STATUS_E_** on error + */ VOS_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, v_S7_t *snr) { - struct statsContext context; - hdd_context_t *pHddCtx; - hdd_station_ctx_t *pHddStaCtx; - eHalStatus hstatus; - unsigned long rc; - int valid; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + eHalStatus hstatus; + int valid; + int ret; + void *cookie; + struct hdd_request *request; + struct snr_priv *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; - ENTER(); - if (NULL == pAdapter) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Invalid context, pAdapter", __func__); - return VOS_STATUS_E_FAULT; - } + ENTER(); - pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - valid = wlan_hdd_validate_context(pHddCtx); - if (0 != valid) - return VOS_STATUS_E_FAULT; + if (NULL == pAdapter) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Invalid context, pAdapter", __func__); + return VOS_STATUS_E_FAULT; + } - pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - init_completion(&context.completion); - context.pAdapter = pAdapter; - context.magic = SNR_CONTEXT_MAGIC; + valid = wlan_hdd_validate_context(pHddCtx); + if (0 != valid) + return VOS_STATUS_E_FAULT; - hstatus = sme_GetSnr(pHddCtx->hHal, hdd_GetSnrCB, - pHddStaCtx->conn_info.staId[ 0 ], - pHddStaCtx->conn_info.bssId, - &context); - if (eHAL_STATUS_SUCCESS != hstatus) - { - hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Unable to retrieve RSSI", - __func__); - /* we'll returned a cached value below */ - } - else - { - /* request was sent -- wait for the response */ - rc = wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); - if (!rc) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while retrieving SNR")); - /* we'll now returned a cached value below */ - } - } + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - /* either we never sent a request, we sent a request and received a - response or we sent a request and timed out. if we never sent a - request or if we sent a request and got a response, we want to - clear the magic out of paranoia. if we timed out there is a - race condition such that the callback function could be - executing at the same time we are. of primary concern is if the - callback function had already verified the "magic" but had not - yet set the completion variable when a timeout occurred. we - serialize these activities by invalidating the magic while - holding a shared spinlock which will cause us to block if the - callback is currently executing */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Request allocation failure", __func__); + return VOS_STATUS_E_FAULT; + } + cookie = hdd_request_cookie(request); - *snr = pAdapter->snr; - EXIT(); - return VOS_STATUS_SUCCESS; + hstatus = sme_GetSnr(pHddCtx->hHal, hdd_get_snr_cb, + pHddStaCtx->conn_info.staId[0], + pHddStaCtx->conn_info.bssId, cookie); + if (eHAL_STATUS_SUCCESS != hstatus) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve SNR", __func__); + /* we'll returned a cached value below */ + } else { + /* request was sent -- wait for the response */ + ret = hdd_request_wait_for_response(request); + if (ret) { + hddLog(VOS_TRACE_LEVEL_ERROR, + FL("SME timed out while retrieving SNR")); + /* we'll now returned a cached value below */ + } else { + /* update the adapter with the fresh results */ + priv = hdd_request_priv(request); + pAdapter->snr = priv->snr; + } + } + + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + hdd_request_put(request); + + *snr = pAdapter->snr; + EXIT(); + return VOS_STATUS_SUCCESS; } void hdd_StatisticsCB( void *pStats, void *pContext ) @@ -3624,6 +3599,27 @@ static int iw_get_range(struct net_device *dev, struct iw_request_info *info, } /** + * iw_power_callback_func() - Callback function registered with PMC + * @context: cookie originally registered with PMC + * @status: status code indicated by PMC state machine + * + * Return: None + */ +static void iw_power_callback_func(void *context, eHalStatus status) +{ + struct hdd_request *request = hdd_request_get(context); + + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Obsolete request", __func__); + return; + } + + hdd_request_complete(request); + hdd_request_put(request); +} + +/** * iw_power_offload_callback_fn() - Callback function registered with PMC to * know status of PMC request * @@ -3636,47 +3632,16 @@ static int iw_get_range(struct net_device *dev, struct iw_request_info *info, static void iw_power_offload_callback_fn(void *context, tANI_U32 session_id, eHalStatus status) { - struct statsContext *stats_context; - - if (NULL == context) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("Bad param, context [%pK]"), - context); - return; - } - - stats_context = (struct statsContext *)context; + struct hdd_request *request; - /* - * there is a race condition that exists between this callback - * function and the caller since the caller could time out either - * before or while this code is executing. we use a spinlock to - * serialize these actions - */ - spin_lock(&hdd_context_lock); - - if (POWER_CONTEXT_MAGIC != stats_context->magic) { - /* the caller presumably timed out */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - FL("Invalid context, magic [%08x]"), - stats_context->magic); - - if (ioctl_debug) - pr_info("%s: Invalid context, magic [%08x]\n", - __func__, stats_context->magic); + request = hdd_request_get(context); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Obsolete request", __func__); return; } - /* context is valid so caller is still waiting */ - - /* paranoia: invalidate the magic */ - stats_context->magic = 0; - /* notify the caller */ - complete(&stats_context->completion); - - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + hdd_request_complete(request); + hdd_request_put(request); } /* Callback function registered with PMC to know status of PMC request */ @@ -3925,142 +3890,135 @@ VOS_STATUS wlan_hdd_get_classAstats(hdd_adapter_t *pAdapter) return VOS_STATUS_SUCCESS; } -static void hdd_get_station_statisticsCB(void *pStats, void *pContext) -{ - struct statsContext *pStatsContext; - tCsrSummaryStatsInfo *pSummaryStats; - tCsrGlobalClassAStatsInfo *pClassAStats; - struct csr_per_chain_rssi_stats_info *per_chain_rssi_stats; - hdd_adapter_t *pAdapter; - - if (ioctl_debug) - { - pr_info("%s: pStats [%pK] pContext [%pK]\n", - __func__, pStats, pContext); - } - - if ((NULL == pStats) || (NULL == pContext)) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Bad param, pStats [%pK] pContext [%pK]", - __func__, pStats, pContext); - return; - } +struct station_stats { + tCsrSummaryStatsInfo summary_stats; + tCsrGlobalClassAStatsInfo class_a_stats; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; +}; - /* there is a race condition that exists between this callback - function and the caller since the caller could time out either - before or while this code is executing. we use a spinlock to - serialize these actions */ - spin_lock(&hdd_context_lock); +/** + * hdd_get_station_statistics_cb() - Get stats callback function + * @stats: pointer to combined station stats + * @context: user context originally registered with SME (always the + * cookie from the request context) + * + * Return: None + */ +static void hdd_get_station_statistics_cb(void *stats, void *context) +{ + struct hdd_request *request; + struct station_stats *priv; + tCsrSummaryStatsInfo *summary_stats; + tCsrGlobalClassAStatsInfo *class_a_stats; + struct csr_per_chain_rssi_stats_info *per_chain_rssi_stats; - pSummaryStats = (tCsrSummaryStatsInfo *)pStats; - pClassAStats = (tCsrGlobalClassAStatsInfo *)( pSummaryStats + 1 ); - per_chain_rssi_stats = (struct csr_per_chain_rssi_stats_info *) - (pClassAStats + 1); - pStatsContext = pContext; - pAdapter = pStatsContext->pAdapter; - if ((NULL == pAdapter) || (STATS_CONTEXT_MAGIC != pStatsContext->magic)) - { - /* the caller presumably timed out so there is nothing we can do */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, pAdapter [%pK] magic [%08x]", - __func__, pAdapter, pStatsContext->magic); - if (ioctl_debug) - { - pr_info("%s: Invalid context, pAdapter [%pK] magic [%08x]\n", - __func__, pAdapter, pStatsContext->magic); - } - return; - } + if (ioctl_debug) { + pr_info("%s: stats [%pK] context [%pK]\n", + __func__, stats, context); + } - /* context is valid so caller is still waiting */ + if (NULL == stats) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Bad param, stats [%pK]", __func__, stats); + return; + } - /* paranoia: invalidate the magic */ - pStatsContext->magic = 0; + request = hdd_request_get(context); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Obsolete request", __func__); + return; + } - /* copy over the stats. do so as a struct copy */ - pAdapter->hdd_stats.summary_stat = *pSummaryStats; - pAdapter->hdd_stats.ClassA_stat = *pClassAStats; - pAdapter->hdd_stats.per_chain_rssi_stats = *per_chain_rssi_stats; + summary_stats = (tCsrSummaryStatsInfo *) stats; + class_a_stats = (tCsrGlobalClassAStatsInfo *) (summary_stats + 1); + per_chain_rssi_stats = (struct csr_per_chain_rssi_stats_info *) + (class_a_stats + 1); + priv = hdd_request_priv(request); - /* notify the caller */ - complete(&pStatsContext->completion); + /* copy over the stats. do so as a struct copy */ + priv->summary_stats = *summary_stats; + priv->class_a_stats = *class_a_stats; + priv->per_chain_rssi_stats = *per_chain_rssi_stats; - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + hdd_request_complete(request); + hdd_request_put(request); } -VOS_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter) +/** + * wlan_hdd_get_station_stats() - Get station statistics + * @pAdapter: adapter for which statistics are desired + * + * Return: VOS_STATUS_SUCCESS if adapter's statistics were updated + */ +VOS_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter) { - hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); - eHalStatus hstatus; - unsigned long rc; - struct statsContext context; - - if (NULL == pAdapter) - { - hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", __func__); - return VOS_STATUS_SUCCESS; - } - - /* we are connected - prepare our callback context */ - init_completion(&context.completion); - context.pAdapter = pAdapter; - context.magic = STATS_CONTEXT_MAGIC; - - /* query only for Summary & Class A statistics */ - hstatus = sme_GetStatistics(WLAN_HDD_GET_HAL_CTX(pAdapter), - eCSR_HDD, - SME_SUMMARY_STATS | - SME_GLOBAL_CLASSA_STATS | - SME_PER_CHAIN_RSSI_STATS, - hdd_get_station_statisticsCB, - 0, // not periodic - FALSE, //non-cached results - pHddStaCtx->conn_info.staId[0], - &context, - pAdapter->sessionId); - if (eHAL_STATUS_SUCCESS != hstatus) - { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Unable to retrieve statistics", - __func__); - /* we'll return with cached values */ - } - else - { - /* request was sent -- wait for the response */ - rc = wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + eHalStatus hstatus; + int ret; + void *cookie; + struct hdd_request *request; + struct station_stats *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (NULL == pAdapter) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", __func__); + return VOS_STATUS_SUCCESS; + } - if (!rc) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while retrieving statistics")); - } - } + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Request allocation failure", __func__); + return VOS_STATUS_E_NOMEM; + } + cookie = hdd_request_cookie(request); + + /* query only for Summary & Class A statistics */ + hstatus = sme_GetStatistics(WLAN_HDD_GET_HAL_CTX(pAdapter), + eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_PER_CHAIN_RSSI_STATS, + hdd_get_station_statistics_cb, + 0, /* not periodic */ + FALSE, /* non-cached results */ + pHddStaCtx->conn_info.staId[0], + cookie, pAdapter->sessionId); + if (eHAL_STATUS_SUCCESS != hstatus) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve statistics", __func__); + /* we'll return with cached values */ + } else { + /* request was sent -- wait for the response */ + ret = hdd_request_wait_for_response(request); + if (ret) { + hddLog(VOS_TRACE_LEVEL_WARN, + FL("SME timed out while retrieving statistics")); + /* we'll returned a cached value below */ + } else { + /* update the adapter with the fresh results */ + priv = hdd_request_priv(request); + pAdapter->hdd_stats.summary_stat = priv->summary_stats; + pAdapter->hdd_stats.ClassA_stat = priv->class_a_stats; + pAdapter->hdd_stats.per_chain_rssi_stats = + priv->per_chain_rssi_stats; + } + } - /* either we never sent a request, we sent a request and received a - response or we sent a request and timed out. if we never sent a - request or if we sent a request and got a response, we want to - clear the magic out of paranoia. if we timed out there is a - race condition such that the callback function could be - executing at the same time we are. of primary concern is if the - callback function had already verified the "magic" but had not - yet set the completion variable when a timeout occurred. we - serialize these activities by invalidating the magic while - holding a shared spinlock which will cause us to block if the - callback is currently executing */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + hdd_request_put(request); - /* either callback updated pAdapter stats or it has cached data */ - return VOS_STATUS_SUCCESS; + /* either callback updated pAdapter stats or it has cached data */ + return VOS_STATUS_SUCCESS; } - /* * Support for the LINKSPEED private command * Per the WiFi framework the response must be of the form @@ -4137,130 +4095,123 @@ static int iw_get_linkspeed_priv(struct net_device *dev, return ret; } -void hdd_get_isolation_cb(struct sir_isolation_resp *isolation, - void *context) -{ - struct statsContext *isolation_context; - int buf = 0; - int length = 0; - char *isolation_output; - union iwreq_data *wrqu; - - if ((NULL == isolation) || (NULL == context)) { - - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Bad param, %s", - __func__, - isolation ? "context is NULL" : "isolation is NULL"); - return; - } +struct isolation_info { + uint32_t isolation_chain0:8; + uint32_t isolation_chain1:8; + uint32_t isolation_chain2:8; + uint32_t isolation_chain3:8; +}; - spin_lock(&hdd_context_lock); +static void hdd_get_isolation_cb(struct sir_isolation_resp *isolation, + void *cookie) +{ + struct hdd_request *request; + struct isolation_info *priv; - isolation_context = context; - if (ISOLATION_CONTEXT_MAGIC != - isolation_context->magic) { + if (!isolation) { + hddLog(LOGE, FL("Bad param")); + return; + } - /* - * the caller presumably timed out so there is nothing - * we can do - */ - spin_unlock(&hdd_context_lock); - hddLog(VOS_TRACE_LEVEL_WARN, - "%s: Invalid context, magic [%08x]", - __func__, - isolation_context->magic); - return; - } + request = hdd_request_get(cookie); + if (!request) { + hddLog(LOGE, FL("Obsolete request")); + return; + } - isolation_output = isolation_context->extra; - wrqu = isolation_context->wrqu; - isolation_context->magic = 0; + priv = hdd_request_priv(request); + priv->isolation_chain0 = isolation->isolation_chain0; + priv->isolation_chain1 = isolation->isolation_chain1; + priv->isolation_chain2 = isolation->isolation_chain2; + priv->isolation_chain3 = isolation->isolation_chain3; - hddLog(LOG1, "%s: chain1 %d chain2 %d chain3 %d chain4 %d", __func__, - isolation->isolation_chain0, isolation->isolation_chain1, - isolation->isolation_chain2, isolation->isolation_chain3); + hdd_request_complete(request); + hdd_request_put(request); +} - length = scnprintf((isolation_output), WE_MAX_STR_LEN, "\n"); - buf = scnprintf - ( - (isolation_output + length), WE_MAX_STR_LEN - length, - "isolation chain 0 : %d\n", - isolation->isolation_chain0 - ); - length += buf; - buf = scnprintf - ( - (isolation_output + length), WE_MAX_STR_LEN - length, - "isolation chain 1 : %d\n", - isolation->isolation_chain1 - ); - length += buf; - buf = scnprintf - ( - (isolation_output + length), WE_MAX_STR_LEN - length, - "isolation chain 2 : %d\n", - isolation->isolation_chain2 - ); - length += buf; - buf = scnprintf - ( - (isolation_output + length), WE_MAX_STR_LEN - length, - "isolation chain 3 : %d\n", - isolation->isolation_chain3 - ); - length += buf; +static void hdd_post_isolation(union iwreq_data *wrqu, char *extra, + struct isolation_info *isolation) +{ + int buf = 0; + int length = 0; - wrqu->data.length = length + 1; + hddLog(LOG1, "%s: chain1 %d chain2 %d chain3 %d chain4 %d", __func__, + isolation->isolation_chain0, isolation->isolation_chain1, + isolation->isolation_chain2, isolation->isolation_chain3); - /* notify the caller */ - complete(&isolation_context->completion); + length = scnprintf((extra), WE_MAX_STR_LEN, "\n"); + buf = scnprintf((extra + length), WE_MAX_STR_LEN - length, + "isolation chain 0 : %d\n", + isolation->isolation_chain0); + length += buf; + buf = scnprintf((extra + length), WE_MAX_STR_LEN - length, + "isolation chain 1 : %d\n", + isolation->isolation_chain1); + length += buf; + buf = scnprintf((extra + length), WE_MAX_STR_LEN - length, + "isolation chain 2 : %d\n", + isolation->isolation_chain2); + length += buf; + buf = scnprintf((extra + length), WE_MAX_STR_LEN - length, + "isolation chain 3 : %d\n", + isolation->isolation_chain3); + length += buf; - /* serialization is complete */ - spin_unlock(&hdd_context_lock); + wrqu->data.length = length + 1; } static int wlan_hdd_get_isolation(hdd_adapter_t *adapter, - union iwreq_data *wrqu, char *extra) + union iwreq_data *wrqu, char *extra) { - eHalStatus hstatus; - int ret; - struct statsContext context; + eHalStatus hstatus; + int ret; + void *cookie; + struct hdd_request *request; + struct isolation_info *priv; + static const struct hdd_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 8000, + }; + + if (NULL == adapter) { + hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", + __func__); + return -EINVAL; + } - if (NULL == adapter) { - hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", - __func__); - return -EINVAL; - } + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Request allocation failure", + __func__); + return VOS_STATUS_E_NOMEM; + } + cookie = hdd_request_cookie(request); - init_completion(&context.completion); - context.magic = ISOLATION_CONTEXT_MAGIC; - context.extra = extra; - context.wrqu = wrqu; + hstatus = sme_get_isolation(WLAN_HDD_GET_HAL_CTX(adapter), + cookie, + hdd_get_isolation_cb); + if (eHAL_STATUS_SUCCESS != hstatus) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Unable to retrieve isolation", + __func__); + ret = -EFAULT; + } else { + ret = hdd_request_wait_for_response(request); + if (ret) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: SME timed out while retrieving isolation", + __func__); + ret = -ETIMEDOUT; + } else { + priv = hdd_request_priv(request); + hdd_post_isolation(wrqu, extra, priv); + ret = 0; + } + } - hstatus = sme_get_isolation(WLAN_HDD_GET_HAL_CTX(adapter), - &context, - hdd_get_isolation_cb); - if (eHAL_STATUS_SUCCESS != hstatus) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: Unable to retrieve isolation", - __func__); - ret = -EFAULT; - } else { - if (!wait_for_completion_timeout(&context.completion, - msecs_to_jiffies(8000))) { - hddLog(VOS_TRACE_LEVEL_ERROR, - "%s: SME timed out while retrieving isolation", - __func__); - ret = -ETIMEDOUT; - } else - ret = 0; - } + hdd_request_put(request); - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); - return ret; + return ret; } static int __iw_get_isolation(struct net_device *dev, @@ -4401,7 +4352,12 @@ VOS_STATUS wlan_hdd_set_powersave(hdd_adapter_t *pAdapter, int mode) { hdd_context_t *pHddCtx; eHalStatus status; - struct statsContext context; + void *cookie; + struct hdd_request *request; + static const struct hdd_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_POWER, + }; if (NULL == pAdapter) { @@ -4409,15 +4365,18 @@ VOS_STATUS wlan_hdd_set_powersave(hdd_adapter_t *pAdapter, int mode) return VOS_STATUS_E_FAULT; } + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Request allocation failure", __func__); + return VOS_STATUS_E_NOMEM; + } + cookie = hdd_request_cookie(request); + hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "power mode=%d", mode); pHddCtx = WLAN_HDD_GET_CTX(pAdapter); - init_completion(&context.completion); - - context.pAdapter = pAdapter; - context.magic = POWER_CONTEXT_MAGIC; - if (DRIVER_POWER_MODE_ACTIVE == mode) { hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s:Wlan driver Entering " @@ -4428,20 +4387,16 @@ VOS_STATUS wlan_hdd_set_powersave(hdd_adapter_t *pAdapter, int mode) * this means we are disconnected */ status = sme_PsOffloadDisablePowerSave(WLAN_HDD_GET_HAL_CTX(pAdapter), - iw_power_offload_callback_fn, &context, + iw_power_offload_callback_fn, cookie, pAdapter->sessionId); if (eHAL_STATUS_PMC_PENDING == status) { - unsigned long rc; - /* request was sent -- wait for the response */ - rc = wait_for_completion_timeout( - &context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_POWER)); - - if (!rc) { - hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while disabling power save")); + if (hdd_request_wait_for_response(request)) { + hddLog(VOS_TRACE_LEVEL_WARN, + FL("SME timed out while requesting full power")); } } + hdd_request_put(request); + if (pHddCtx->cfg_ini->fIsBmpsEnabled) sme_ConfigDisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE); @@ -4468,9 +4423,7 @@ VOS_STATUS wlan_hdd_set_powersave(hdd_adapter_t *pAdapter, int mode) "enabled in the cfg"); } } - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); + return VOS_STATUS_SUCCESS; } @@ -6081,45 +6034,39 @@ static int __iw_setint_getnone(struct net_device *dev, { case 0: //Full Power { - struct statsContext context; + struct hdd_request *request; + void *cookie; + static const struct hdd_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_POWER, + }; eHalStatus status = eHAL_STATUS_FAILURE; - init_completion(&context.completion); - - context.pAdapter = pAdapter; - context.magic = POWER_CONTEXT_MAGIC; - if (NULL == hHal) return -EINVAL; - status = sme_RequestFullPower(WLAN_HDD_GET_HAL_CTX(pAdapter), - iw_power_callback_fn, &context, - eSME_FULL_PWR_NEEDED_BY_HDD); - if (eHAL_STATUS_PMC_PENDING == status) - { - unsigned long rc; - rc = wait_for_completion_timeout( - &context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_POWER)); + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Request allocation failure", __func__); + return VOS_STATUS_E_NOMEM; + } - if (!rc) { + cookie = hdd_request_cookie(request); + status = sme_RequestFullPower(hHal, + iw_power_callback_func, cookie, + eSME_FULL_PWR_NEEDED_BY_HDD); + if (eHAL_STATUS_PMC_PENDING == status) { + if(hdd_request_wait_for_response(request)) hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while requesting full power")); - } + FL("SME timed out while requesting full power")); } - /* either we have a response or we timed out. if we timed - out there is a race condition such that the callback - function could be executing at the same time we are. of - primary concern is if the callback function had already - verified the "magic" but had not yet set the completion - variable when a timeout occurred. we serialize these - activities by invalidating the magic while holding a - shared spinlock which will cause us to block if the - callback is currently executing */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); - + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + hdd_request_put(request); hddLog(LOGE, "iwpriv Full Power completed"); break; } @@ -6137,44 +6084,38 @@ static int __iw_setint_getnone(struct net_device *dev, break; case 3: //Request Bmps { - struct statsContext context; + struct hdd_request *request; + void *cookie; + static const struct hdd_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_POWER, + }; eHalStatus status = eHAL_STATUS_FAILURE; - init_completion(&context.completion); - - context.pAdapter = pAdapter; - context.magic = POWER_CONTEXT_MAGIC; - if (NULL == hHal) return -EINVAL; + request = hdd_request_alloc(¶ms); + if (!request) { + hddLog(VOS_TRACE_LEVEL_ERROR, + "%s: Request allocation failure", __func__); + return VOS_STATUS_E_NOMEM; + } + + cookie = hdd_request_cookie(request); status = sme_RequestBmps(WLAN_HDD_GET_HAL_CTX(pAdapter), - iw_power_callback_fn, &context); - if (eHAL_STATUS_PMC_PENDING == status) - { - unsigned long rc; - rc = wait_for_completion_timeout( - &context.completion, - msecs_to_jiffies(WLAN_WAIT_TIME_POWER)); - if (!rc) { + iw_power_callback_func, cookie); + if (eHAL_STATUS_PMC_PENDING == status) { + if (hdd_request_wait_for_response(request)) hddLog(VOS_TRACE_LEVEL_ERROR, - FL("SME timed out while requesting BMPS")); - } + FL("SME timed out while requesting BMPS")); } - /* either we have a response or we timed out. if we - timed out there is a race condition such that the - callback function could be executing at the same - time we are. of primary concern is if the callback - function had already verified the "magic" but had - not yet set the completion variable when a timeout - occurred. we serialize these activities by - invalidating the magic while holding a shared - spinlock which will cause us to block if the - callback is currently executing */ - spin_lock(&hdd_context_lock); - context.magic = 0; - spin_unlock(&hdd_context_lock); - + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + hdd_request_put(request); hddLog(LOGE, "iwpriv Request BMPS completed"); break; } diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c index ef97c56142b..db7c8fe3c86 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c @@ -4845,7 +4845,8 @@ static int wma_passpoint_match_event_handler(void *handle, struct wifi_passpoint_match *dest_match; tSirWifiScanResult *dest_ap; uint8_t *buf_ptr; - + uint32_t buf_len = 0; + bool excess_data = false; tpAniSirGlobal pMac = (tpAniSirGlobal )vos_get_context( VOS_MODULE_ID_PE, wma->vos_context); if (!pMac) { @@ -4864,14 +4865,28 @@ static int wma_passpoint_match_event_handler(void *handle, event = param_buf->fixed_param; buf_ptr = (uint8_t *)param_buf->fixed_param; - /* - * All the below lengths are UINT32 and summing up and checking - * against a constant should not be an issue. - */ - if ((sizeof(*event) + event->ie_length + event->anqp_length) > - WMA_SVC_MSG_MAX_SIZE) { - WMA_LOGE("IE Length: %d or ANQP Length: %d is huge", - event->ie_length, event->anqp_length); + do { + if (event->ie_length > (WMA_SVC_MSG_MAX_SIZE)) { + excess_data = true; + break; + } else { + buf_len = event->ie_length; + } + + if (event->anqp_length > (WMA_SVC_MSG_MAX_SIZE)) { + excess_data = true; + break; + } else { + buf_len += event->anqp_length; + } + } while (0); + + if (excess_data || buf_len > (WMA_SVC_MSG_MAX_SIZE - sizeof(*event)) || + buf_len > (WMA_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) || + (event->ie_length + event->anqp_length) > param_buf->num_bufp) { + WMA_LOGE("IE Length: %d or ANQP Length: %d is huge, num_bufp %d", + event->ie_length, event->anqp_length, + param_buf->num_bufp); return -EINVAL; } if (event->ssid.ssid_len > SIR_MAC_MAX_SSID_LENGTH) { @@ -4879,8 +4894,7 @@ static int wma_passpoint_match_event_handler(void *handle, __func__, event->ssid.ssid_len); event->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; } - dest_match = vos_mem_malloc(sizeof(*dest_match) + - event->ie_length + event->anqp_length); + dest_match = vos_mem_malloc(sizeof(*dest_match) + buf_len); if (!dest_match) { WMA_LOGE("%s: vos_mem_malloc failed", __func__); return -EINVAL; @@ -9281,7 +9295,10 @@ wma_action_frame_filter_mac_event_handler(void *handle, u_int8_t *event_buf, WMA_LOGA(FL("Invalid fixed param")); return -EINVAL; } - + if (event->vdev_id >= wma_handle->max_bssid) { + WMA_LOGA(FL("Invalid vdev id")); + return -EINVAL; + } intr = &wma_handle->interfaces[event->vdev_id]; /* command is in progess */ if(!intr->action_frame_filter) { @@ -35293,6 +35310,7 @@ static int wma_apfind_evt_handler(void *handle, u_int8_t *event, u_int8_t ssid_tmp[WMI_MAX_SSID_LEN + 1]; u_int8_t *mac; u_int32_t vdev_id; + u_int32_t buf_len; if (!param_buf) { WMA_LOGE("Invalid APFIND event buffer"); @@ -35300,8 +35318,36 @@ static int wma_apfind_evt_handler(void *handle, u_int8_t *event, } apfind_event_hdr = param_buf->hdr; - WMA_LOGD("APFIND event received, id=%d, data_length=%d", - apfind_event_hdr->event_type, apfind_event_hdr->data_len); + WMA_LOGD("APFIND event received, id=%d, data_len=%d", + apfind_event_hdr->event_type, apfind_event_hdr->data_len); + + /* data_len = WMI_TLV_HDR_SIZE + length of data */ + if (apfind_event_hdr->data_len <= WMI_TLV_HDR_SIZE) { + WMA_LOGE("APFIND event with no data"); + return -EINVAL; + } + + buf_len = param_buf->num_data; + if (buf_len != (apfind_event_hdr->data_len - WMI_TLV_HDR_SIZE)) { + WMA_LOGE("APFIND event with unmatched len: %u - %u", + buf_len, apfind_event_hdr->data_len); + return -EINVAL; + } + + if ((apfind_event_hdr->data_len > + (len - sizeof(wmi_apfind_event_hdr))) || + (apfind_event_hdr->data_len > + (WMA_SVC_MSG_MAX_SIZE - sizeof(wmi_apfind_event_hdr)))) { + WMA_LOGE("APFIND event with invalid data_len: %u", + apfind_event_hdr->data_len); + return -EINVAL; + } + + if (buf_len < WMI_MAX_SSID_LEN + IEEE80211_ADDR_LEN) { + WMA_LOGE("APFIND event with invalid buf_len: %u", buf_len); + return -EINVAL; + } + buf = param_buf->data; A_MEMZERO(ssid_tmp, sizeof(ssid_tmp)); A_MEMCPY(ssid_tmp, buf, WMI_MAX_SSID_LEN); @@ -35310,12 +35356,10 @@ static int wma_apfind_evt_handler(void *handle, u_int8_t *event, buf = ¶m_buf->data[WMI_MAX_SSID_LEN]; mac = buf; - WMA_LOGD("%s, APFIND dump mac=0x%08X-0x%08X", - __func__, *(u_int32_t *)buf, *(u_int32_t *)(buf + sizeof(u_int32_t))); + WMA_LOGD("%s, APFIND dump mac=%pM", __func__, mac); - if (apfind_event_hdr->data_len >= - (WMI_MAX_SSID_LEN + IEEE80211_ADDR_LEN + sizeof(vdev_id) - + sizeof(apfind_event_hdr->tlv_header))) { + if (buf_len >= + (WMI_MAX_SSID_LEN + IEEE80211_ADDR_LEN + sizeof(vdev_id))) { /* FW had the tlv_header len calculated into the data_len */ buf = ¶m_buf->data[WMI_MAX_SSID_LEN + IEEE80211_ADDR_LEN]; vdev_id = *(u_int32_t*) buf; diff --git a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_tlv_helper.c b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_tlv_helper.c index 7b604c0ee2e..960c38d21ed 100644 --- a/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_tlv_helper.c +++ b/drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_tlv_helper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014,2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014,2017-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -375,6 +375,7 @@ wmitlv_check_and_pad_tlvs( wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL; A_UINT32 remaining_expected_tlvs=0xFFFFFFFF; A_UINT32 len_wmi_cmd_struct_buf; + A_UINT32 free_buf_len; /* Get the number of TLVs for this command/event */ if (wmitlv_get_attributes(is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS, &attr_struct_ptr) != 0) @@ -426,6 +427,12 @@ wmitlv_check_and_pad_tlvs( A_UINT32 curr_tlv_len = WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); int num_padding_bytes = 0; + free_buf_len = param_buf_len - (buf_idx + WMI_TLV_HDR_SIZE); + if (curr_tlv_len > free_buf_len) { + wmi_tlv_print_error("%s: TLV length overflow", __func__); + goto Error_wmitlv_check_and_pad_tlvs; + } + /* Get the attributes of the TLV with the given order in "tlv_index" */ wmi_tlv_OS_MEMZERO(&attr_struct_ptr,sizeof(wmitlv_attributes_struc)); if (wmitlv_get_attributes(is_cmd_id, wmi_cmd_event_id, tlv_index, &attr_struct_ptr) != 0) @@ -479,17 +486,19 @@ wmitlv_check_and_pad_tlvs( { A_UINT32 in_tlv_len = 0; - if (curr_tlv_len != 0) - { + if (curr_tlv_len != 0) { in_tlv_len = WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); in_tlv_len += WMI_TLV_HDR_SIZE; + if (in_tlv_len > curr_tlv_len) { + wmi_tlv_print_error("%s: Invalid in_tlv_len=%d", + __func__, in_tlv_len); + goto Error_wmitlv_check_and_pad_tlvs; + } tlv_size_diff = in_tlv_len - attr_struct_ptr.tag_struct_size; num_of_elems = curr_tlv_len/in_tlv_len; wmi_tlv_print_verbose("%s: WARN: TLV array of structures in_tlv_len=%d struct_size:%d diff:%d num_of_elems=%d \n", __func__, in_tlv_len, attr_struct_ptr.tag_struct_size, tlv_size_diff, num_of_elems); - } - else - { + } else { tlv_size_diff = 0; num_of_elems = 0; } @@ -568,40 +577,54 @@ wmitlv_check_and_pad_tlvs( if (tlv_size_diff < 0) { - /* Incoming structure size is smaller than expected size then this needs padding for each element in the array */ + /* + * Incoming structure size is smaller than expected size + * then this needs padding for each element in the array + */ /* Find amount of bytes to be padded for one element */ num_padding_bytes = tlv_size_diff * -1; - /* Move subsequent TLVs by number of bytes to be padded for all elements */ - if (param_buf_len > (buf_idx + curr_tlv_len)) - { + /* + * Move subsequent TLVs by number of bytes to be + * padded for all elements + */ + if (free_buf_len < attr_struct_ptr.tag_struct_size * + num_of_elems || + param_buf_len < buf_idx + curr_tlv_len + + num_padding_bytes * num_of_elems) { + wmi_tlv_print_error("%s: Insufficent buffer\n", + __func__); + goto Error_wmitlv_check_and_pad_tlvs; + } else { src_addr = buf_ptr + curr_tlv_len; - dst_addr = buf_ptr + curr_tlv_len + (num_padding_bytes * num_of_elems); + dst_addr = buf_ptr + curr_tlv_len + + num_padding_bytes * num_of_elems; buf_mov_len = param_buf_len - (buf_idx + curr_tlv_len); wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, buf_mov_len); } - /* Move subsequent elements of array down by number of bytes to be padded for one element and alse set padding bytes to zero */ + /* + * Move subsequent elements of array down by number of bytes + * to be padded for one element and alse set padding bytes + * to zero + */ tlv_buf_ptr = buf_ptr; - for(i=0; i<num_of_elems; i++) + for (i = 0; i < num_of_elems - 1; i++) { src_addr = tlv_buf_ptr + in_tlv_len; - if (i != (num_of_elems-1)) - { - /* Need not move anything for last element in the array */ - dst_addr = tlv_buf_ptr + in_tlv_len + num_padding_bytes; - buf_mov_len = curr_tlv_len - ((i+1) * in_tlv_len); - - wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, buf_mov_len); - } + dst_addr = tlv_buf_ptr + in_tlv_len + num_padding_bytes; + buf_mov_len = curr_tlv_len - ((i + 1) * in_tlv_len); + wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, buf_mov_len); /* Set the padding bytes to zeroes */ wmi_tlv_OS_MEMZERO(src_addr, num_padding_bytes); tlv_buf_ptr += attr_struct_ptr.tag_struct_size; } + src_addr = tlv_buf_ptr + in_tlv_len; + wmi_tlv_OS_MEMZERO(src_addr, num_padding_bytes); /* Update the number of padding bytes to total number of bytes padded for all elements in the array */ num_padding_bytes = num_padding_bytes * num_of_elems; diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c b/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c index 7a7be6ddade..8e4201a54cc 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1892,7 +1892,7 @@ dbglog_print_raw_data(A_UINT32 *buffer, A_UINT32 length) char parseArgsString[DBGLOG_PARSE_ARGS_STRING_LENGTH]; char *dbgidString; - while (count < length) { + while (count + 1 < length) { debugid = DBGLOG_GET_DBGID(buffer[count + 1]); moduleid = DBGLOG_GET_MODULEID(buffer[count + 1]); @@ -1904,12 +1904,16 @@ dbglog_print_raw_data(A_UINT32 *buffer, A_UINT32 length) OS_MEMZERO(parseArgsString, sizeof(parseArgsString)); totalWriteLen = 0; + if (!numargs || (count + numargs + 2 > length)) + goto skip_args_processing; + for (curArgs = 0; curArgs < numargs; curArgs++){ // Using sprintf_s instead of sprintf, to avoid length overflow writeLen = snprintf(parseArgsString + totalWriteLen, DBGLOG_PARSE_ARGS_STRING_LENGTH - totalWriteLen, "%x ", buffer[count + 2 + curArgs]); totalWriteLen += writeLen; } +skip_args_processing: if (debugid < MAX_DBG_MSGS){ dbgidString = DBG_MSG_ARR[moduleid][debugid]; if (dbgidString != NULL) { @@ -2398,6 +2402,11 @@ dbglog_parse_debug_logs(ol_scn_t scn, u_int8_t *data, u_int32_t datalen) len = param_buf->num_bufp; } + if (len < sizeof(dropped)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid length\n")); + return -1; + } + dropped = *((A_UINT32 *)datap); if (dropped > 0) { AR_DEBUG_PRINTF(ATH_DEBUG_TRC , ("%d log buffers are dropped \n", dropped)); diff --git a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c index 0bf7982d53f..ed6db176618 100644 --- a/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c +++ b/drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -78,6 +78,8 @@ static struct ath_pktlog_info *g_pktlog_info; static struct proc_dir_entry *g_pktlog_pde; +static DEFINE_MUTEX(proc_mutex); + static int pktlog_attach(struct ol_softc *sc); static void pktlog_detach(struct ol_softc *sc); static int pktlog_open(struct inode *i, struct file *f); @@ -226,9 +228,11 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ol_ath_generic_softc_handle scn; struct ol_pktlog_dev_t *pl_dev; + mutex_lock(&proc_mutex); scn = (ol_ath_generic_softc_handle) ctl->extra1; if (!scn) { + mutex_unlock(&proc_mutex); printk("%s: Invalid scn context\n", __func__); ASSERT(0); return -EINVAL; @@ -237,6 +241,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, pl_dev = get_pl_handle((struct ol_softc *)scn); if (!pl_dev) { + mutex_unlock(&proc_mutex); printk("%s: Invalid pktlog context\n", __func__); ASSERT(0); return -ENODEV; @@ -266,6 +271,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ctl->data = NULL; ctl->maxlen = 0; + mutex_unlock(&proc_mutex); return ret; } @@ -283,9 +289,11 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ol_ath_generic_softc_handle scn; struct ol_pktlog_dev_t *pl_dev; + mutex_lock(&proc_mutex); scn = (ol_ath_generic_softc_handle) ctl->extra1; if (!scn) { + mutex_unlock(&proc_mutex); printk("%s: Invalid scn context\n", __func__); ASSERT(0); return -EINVAL; @@ -294,6 +302,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, pl_dev = get_pl_handle((struct ol_softc *)scn); if (!pl_dev) { + mutex_unlock(&proc_mutex); printk("%s: Invalid pktlog handle\n", __func__); ASSERT(0); return -ENODEV; @@ -318,6 +327,7 @@ ATH_SYSCTL_DECL(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ctl->data = NULL; ctl->maxlen = 0; + mutex_unlock(&proc_mutex); return ret; } diff --git a/drivers/staging/qcacld-2.0/Kbuild b/drivers/staging/qcacld-2.0/Kbuild index ac9611cf108..b6a196baf13 100644 --- a/drivers/staging/qcacld-2.0/Kbuild +++ b/drivers/staging/qcacld-2.0/Kbuild @@ -442,6 +442,7 @@ HDD_OBJS := $(HDD_SRC_DIR)/wlan_hdd_assoc.o \ $(HDD_SRC_DIR)/wlan_hdd_main.o \ $(HDD_SRC_DIR)/wlan_hdd_memdump.o \ $(HDD_SRC_DIR)/wlan_hdd_oemdata.o \ + $(HDD_SRC_DIR)/wlan_hdd_request_manager.o \ $(HDD_SRC_DIR)/wlan_hdd_scan.o \ $(HDD_SRC_DIR)/wlan_hdd_softap_tx_rx.o \ $(HDD_SRC_DIR)/wlan_hdd_tx_rx.o \ diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 65243832519..98a87503378 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -511,15 +511,23 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx, } else if (header->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION) { + struct usb_interface_assoc_descriptor *d; + + d = (struct usb_interface_assoc_descriptor *)header; + if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) { + dev_warn(ddev, + "config %d has an invalid interface association descriptor of length %d, skipping\n", + cfgno, d->bLength); + continue; + } + if (iad_num == USB_MAXIADS) { dev_warn(ddev, "found more Interface " "Association Descriptors " "than allocated for in " "configuration %d\n", cfgno); } else { - config->intf_assoc[iad_num] = - (struct usb_interface_assoc_descriptor - *)header; + config->intf_assoc[iad_num] = d; iad_num++; } @@ -820,10 +828,12 @@ int usb_get_bos_descriptor(struct usb_device *dev) for (i = 0; i < num; i++) { buffer += length; cap = (struct usb_dev_cap_header *)buffer; - length = cap->bLength; - if (total_len < length) + if (total_len < sizeof(*cap) || total_len < cap->bLength) { + dev->bos->desc->bNumDeviceCaps = i; break; + } + length = cap->bLength; total_len -= length; if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { diff --git a/drivers/usb/dwc3/dbm-1_4.c b/drivers/usb/dwc3/dbm-1_4.c index 661a938e055..1caf7983f60 100644 --- a/drivers/usb/dwc3/dbm-1_4.c +++ b/drivers/usb/dwc3/dbm-1_4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -372,7 +372,6 @@ static int msm_dbm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct dbm *dbm; struct resource *res; - int ret = 0; dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL); if (!dbm_data) @@ -382,24 +381,21 @@ static int msm_dbm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory base resource\n"); - ret = -ENODEV; - goto free_dbm_data; + return -ENODEV; } dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!dbm_data->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL); if (!dbm) { dev_err(&pdev->dev, "not enough memory\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm->dev = dev; @@ -418,20 +414,6 @@ static int msm_dbm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dbm); return usb_add_dbm(dbm); - -free_dbm_data: - kfree(dbm_data); - return ret; -} - -static int msm_dbm_remove(struct platform_device *pdev) -{ - struct dbm *dbm = platform_get_drvdata(pdev); - - kfree(dbm); - kfree(dbm_data); - - return 0; } static const struct of_device_id msm_dbm_1_4_id_table[] = { @@ -444,7 +426,6 @@ MODULE_DEVICE_TABLE(of, msm_dbm_1_4_id_table); static struct platform_driver msm_dbm_driver = { .probe = msm_dbm_probe, - .remove = msm_dbm_remove, .driver = { .name = "msm-usb-dbm-1-4", .of_match_table = of_match_ptr(msm_dbm_1_4_id_table), diff --git a/drivers/usb/dwc3/dbm-1_5.c b/drivers/usb/dwc3/dbm-1_5.c index 2a3609ef6ff..81964e9818b 100644 --- a/drivers/usb/dwc3/dbm-1_5.c +++ b/drivers/usb/dwc3/dbm-1_5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -387,7 +387,6 @@ static int msm_dbm_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct dbm *dbm; struct resource *res; - int ret = 0; dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL); if (!dbm_data) @@ -397,24 +396,21 @@ static int msm_dbm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory base resource\n"); - ret = -ENODEV; - goto free_dbm_data; + return -ENODEV; } dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!dbm_data->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL); if (!dbm) { dev_err(&pdev->dev, "not enough memory\n"); - ret = -ENOMEM; - goto free_dbm_data; + return -ENOMEM; } dbm_data->dbm_reset_ep_after_lpm = of_property_read_bool(node, @@ -437,20 +433,6 @@ static int msm_dbm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dbm); return usb_add_dbm(dbm); - -free_dbm_data: - kfree(dbm_data); - return ret; -} - -static int msm_dbm_remove(struct platform_device *pdev) -{ - struct dbm *dbm = platform_get_drvdata(pdev); - - kfree(dbm); - kfree(dbm_data); - - return 0; } static const struct of_device_id msm_dbm_1_5_id_table[] = { @@ -463,7 +445,6 @@ MODULE_DEVICE_TABLE(of, msm_dbm_1_5_id_table); static struct platform_driver msm_dbm_driver = { .probe = msm_dbm_probe, - .remove = msm_dbm_remove, .driver = { .name = "msm-usb-dbm-1-5", .of_match_table = of_match_ptr(msm_dbm_1_5_id_table), diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c index 85bddfab39d..241c28ee5f7 100755 --- a/drivers/video/msm/mdss/mdp3_ctrl.c +++ b/drivers/video/msm/mdss/mdp3_ctrl.c @@ -1504,9 +1504,10 @@ static int mdp3_get_metadata(struct msm_fb_data_type *mfd, } break; case metadata_op_get_ion_fd: - if (mfd->fb_ion_handle) { + if (mfd->fb_ion_handle && mfd->fb_ion_client) { metadata->data.fbmem_ionfd = - dma_buf_fd(mfd->fbmem_buf, 0); + ion_share_dma_buf_fd(mfd->fb_ion_client, + mfd->fb_ion_handle); if (metadata->data.fbmem_ionfd < 0) pr_err("fd allocation failed. fd = %d\n", metadata->data.fbmem_ionfd); diff --git a/fs/dcache.c b/fs/dcache.c index 9a59653d344..613f49902eb 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -214,16 +214,50 @@ static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *c return dentry_string_cmp(cs, ct, tcount); } +struct external_name { + union { + atomic_t count; + struct rcu_head head; + } u; + unsigned char name[]; +}; + +static inline struct external_name *external_name(struct dentry *dentry) +{ + return container_of(dentry->d_name.name, struct external_name, name[0]); +} + static void __d_free(struct rcu_head *head) { struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); WARN_ON(!hlist_unhashed(&dentry->d_alias)); - if (dname_external(dentry)) - kfree(dentry->d_name.name); kmem_cache_free(dentry_cache, dentry); } +static void __d_free_external(struct rcu_head *head) +{ + struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); + kfree(external_name(dentry)); + kmem_cache_free(dentry_cache, dentry); +} + +static void dentry_free(struct dentry *dentry) +{ + if (unlikely(dname_external(dentry))) { + struct external_name *p = external_name(dentry); + if (likely(atomic_dec_and_test(&p->u.count))) { + call_rcu(&dentry->d_u.d_rcu, __d_free_external); + return; + } + } + /* if dentry was never visible to RCU, immediate free is OK */ + if (!(dentry->d_flags & DCACHE_RCUACCESS)) + __d_free(&dentry->d_u.d_rcu); + else + call_rcu(&dentry->d_u.d_rcu, __d_free); +} + /* * no locks, please. */ @@ -234,11 +268,7 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - /* if dentry was never visible to RCU, immediate free is OK */ - if (!(dentry->d_flags & DCACHE_RCUACCESS)) - __d_free(&dentry->d_u.d_rcu); - else - call_rcu(&dentry->d_u.d_rcu, __d_free); + dentry_free(dentry); } /** @@ -303,6 +333,33 @@ static void dentry_unlink_inode(struct dentry * dentry) iput(inode); } +void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry) +{ + spin_lock(&dentry->d_lock); + if (unlikely(dname_external(dentry))) { + struct external_name *p = external_name(dentry); + atomic_inc(&p->u.count); + spin_unlock(&dentry->d_lock); + name->name = p->name; + } else { + memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN); + spin_unlock(&dentry->d_lock); + name->name = name->inline_name; + } +} +EXPORT_SYMBOL(take_dentry_name_snapshot); + +void release_dentry_name_snapshot(struct name_snapshot *name) +{ + if (unlikely(name->name != name->inline_name)) { + struct external_name *p; + p = container_of(name->name, struct external_name, name[0]); + if (unlikely(atomic_dec_and_test(&p->u.count))) + kfree_rcu(p, u.head); + } +} +EXPORT_SYMBOL(release_dentry_name_snapshot); + /* * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held. */ @@ -1251,11 +1308,14 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) */ dentry->d_iname[DNAME_INLINE_LEN-1] = 0; if (name->len > DNAME_INLINE_LEN-1) { - dname = kmalloc(name->len + 1, GFP_KERNEL); - if (!dname) { + size_t size = offsetof(struct external_name, name[1]); + struct external_name *p = kmalloc(size + name->len, GFP_KERNEL); + if (!p) { kmem_cache_free(dentry_cache, dentry); return NULL; } + atomic_set(&p->u.count, 1); + dname = p->name; } else { dname = dentry->d_iname; } @@ -2148,8 +2208,8 @@ EXPORT_SYMBOL(dentry_update_name_case); static void switch_names(struct dentry *dentry, struct dentry *target) { - if (dname_external(target)) { - if (dname_external(dentry)) { + if (unlikely(dname_external(target))) { + if (unlikely(dname_external(dentry))) { /* * Both external: swap the pointers */ @@ -2165,7 +2225,7 @@ static void switch_names(struct dentry *dentry, struct dentry *target) target->d_name.name = target->d_iname; } } else { - if (dname_external(dentry)) { + if (unlikely(dname_external(dentry))) { /* * dentry:external, target:internal. Give dentry's * storage to target and make dentry internal @@ -2187,6 +2247,25 @@ static void switch_names(struct dentry *dentry, struct dentry *target) swap(dentry->d_name.len, target->d_name.len); } +static void copy_name(struct dentry *dentry, struct dentry *target) +{ + struct external_name *old_name = NULL; + if (unlikely(dname_external(dentry))) + old_name = external_name(dentry); + if (unlikely(dname_external(target))) { + atomic_inc(&external_name(target)->u.count); + dentry->d_name = target->d_name; + } else { + memcpy(dentry->d_iname, target->d_name.name, + target->d_name.len + 1); + dentry->d_name.name = dentry->d_iname; + dentry->d_name.len = target->d_name.len; + } + if (old_name && likely(atomic_dec_and_test(&old_name->u.count))) + kfree_rcu(old_name, u.head); +} + + static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) { /* @@ -2273,7 +2352,7 @@ static void __d_move(struct dentry * dentry, struct dentry * target) list_del(&target->d_u.d_child); /* Switch the names.. */ - switch_names(dentry, target); + copy_name(dentry, target); swap(dentry->d_name.hash, target->d_name.hash); /* ... and switch the parents */ diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 1c807d31759..3d0ca74ae54 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -601,7 +601,7 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, { int error; struct dentry *dentry = NULL, *trap; - const char *old_name; + struct name_snapshot old_name; trap = lock_rename(new_dir, old_dir); /* Source or destination directories don't exist? */ @@ -616,19 +616,19 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, if (IS_ERR(dentry) || dentry == trap || dentry->d_inode) goto exit; - old_name = fsnotify_oldname_init(old_dentry->d_name.name); + take_dentry_name_snapshot(&old_name, old_dentry); error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, dentry); if (error) { - fsnotify_oldname_free(old_name); + release_dentry_name_snapshot(&old_name); goto exit; } d_move(old_dentry, dentry); - fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name, + fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name.name, S_ISDIR(old_dentry->d_inode->i_mode), NULL, old_dentry); - fsnotify_oldname_free(old_name); + release_dentry_name_snapshot(&old_name); unlock_rename(new_dir, old_dir); dput(dentry); return old_dentry; diff --git a/fs/namei.c b/fs/namei.c index 022771a0e3b..d052970f614 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3802,7 +3802,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, { int error; int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); - const unsigned char *old_name; + struct name_snapshot old_name; if (old_dentry->d_inode == new_dentry->d_inode) return 0; @@ -3821,16 +3821,16 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (!old_dir->i_op->rename) return -EPERM; - old_name = fsnotify_oldname_init(old_dentry->d_name.name); + take_dentry_name_snapshot(&old_name, old_dentry); if (is_dir) error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); if (!error) - fsnotify_move(old_dir, new_dir, old_name, is_dir, + fsnotify_move(old_dir, new_dir, old_name.name, is_dir, new_dentry->d_inode, old_dentry); - fsnotify_oldname_free(old_name); + release_dentry_name_snapshot(&old_name); return error; } diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 4bb21d67d9b..aaba571cdfb 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -105,16 +105,20 @@ int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) if (unlikely(!fsnotify_inode_watches_children(p_inode))) __fsnotify_update_child_dentry_flags(p_inode); else if (p_inode->i_fsnotify_mask & mask) { + struct name_snapshot name; + /* we are notifying a parent so come up with the new mask which * specifies these are events which came from a child. */ mask |= FS_EVENT_ON_CHILD; + take_dentry_name_snapshot(&name, dentry); if (path) ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH, - dentry->d_name.name, 0); + name.name, 0); else ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, - dentry->d_name.name, 0); + name.name, 0); + release_dentry_name_snapshot(&name); } dput(parent); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 9be5ac960fd..7ecc64bc369 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -412,4 +412,11 @@ static inline bool d_mountpoint(struct dentry *dentry) extern int sysctl_vfs_cache_pressure; +struct name_snapshot { + const char *name; + char inline_name[DNAME_INLINE_LEN]; +}; +void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *); +void release_dentry_name_snapshot(struct name_snapshot *); + #endif /* __LINUX_DCACHE_H */ diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index a78680a92db..5d72731d026 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -308,35 +308,4 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) } } -#if defined(CONFIG_FSNOTIFY) /* notify helpers */ - -/* - * fsnotify_oldname_init - save off the old filename before we change it - */ -static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name) -{ - return kstrdup(name, GFP_KERNEL); -} - -/* - * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init - */ -static inline void fsnotify_oldname_free(const unsigned char *old_name) -{ - kfree(old_name); -} - -#else /* CONFIG_FSNOTIFY */ - -static inline const char *fsnotify_oldname_init(const unsigned char *name) -{ - return NULL; -} - -static inline void fsnotify_oldname_free(const unsigned char *old_name) -{ -} - -#endif /* CONFIG_FSNOTIFY */ - #endif /* _LINUX_FS_NOTIFY_H */ diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index adf0885153f..76ef2a44702 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -77,6 +77,7 @@ struct snd_rawmidi_runtime { size_t xruns; /* over/underruns counter */ /* misc */ spinlock_t lock; + struct mutex realloc_mutex; wait_queue_head_t sleep; /* event handler (new bytes, input only) */ void (*event)(struct snd_rawmidi_substream *substream); diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index fca1db35ac0..9f0fd880028 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -720,6 +720,7 @@ struct usb_interface_assoc_descriptor { __u8 iFunction; } __attribute__ ((packed)); +#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8 /*-------------------------------------------------------------------------*/ diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index 9ce62282edb..27260cac2d4 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -518,13 +518,11 @@ static struct tag_ref *get_tag_ref(tag_t full_tag, DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n", full_tag); - spin_lock_bh(&uid_tag_data_tree_lock); tr_entry = lookup_tag_ref(full_tag, &utd_entry); BUG_ON(IS_ERR_OR_NULL(utd_entry)); if (!tr_entry) tr_entry = new_tag_ref(full_tag, utd_entry); - spin_unlock_bh(&uid_tag_data_tree_lock); if (utd_res) *utd_res = utd_entry; DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n", @@ -2012,6 +2010,7 @@ static int ctrl_cmd_delete(const char *input) /* Delete socket tags */ spin_lock_bh(&sock_tag_list_lock); + spin_lock_bh(&uid_tag_data_tree_lock); node = rb_first(&sock_tag_tree); while (node) { st_entry = rb_entry(node, struct sock_tag, sock_node); @@ -2041,6 +2040,7 @@ static int ctrl_cmd_delete(const char *input) list_del(&st_entry->list); } } + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); sock_tag_tree_erase(&st_to_free_tree); @@ -2245,10 +2245,12 @@ static int ctrl_cmd_tag(const char *input) full_tag = combine_atag_with_uid(acct_tag, uid); spin_lock_bh(&sock_tag_list_lock); + spin_lock_bh(&uid_tag_data_tree_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry); if (IS_ERR(tag_ref_entry)) { res = PTR_ERR(tag_ref_entry); + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); goto err_put; } @@ -2282,9 +2284,14 @@ static int ctrl_cmd_tag(const char *input) pr_err("qtaguid: ctrl_tag(%s): " "socket tag alloc failed\n", input); + BUG_ON(tag_ref_entry->num_sock_tags <= 0); + tag_ref_entry->num_sock_tags--; + free_tag_ref_from_utd_entry(tag_ref_entry, + uid_tag_data_entry); + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); res = -ENOMEM; - goto err_tag_unref_put; + goto err_put; } sock_tag_entry->sk = el_socket->sk; sock_tag_entry->socket = el_socket; @@ -2309,11 +2316,11 @@ static int ctrl_cmd_tag(const char *input) else list_add(&sock_tag_entry->list, &pqd_entry->sock_tag_list); - spin_unlock_bh(&uid_tag_data_tree_lock); sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree); atomic64_inc(&qtu_events.sockets_tagged); } + spin_unlock_bh(&uid_tag_data_tree_lock); spin_unlock_bh(&sock_tag_list_lock); /* We keep the ref to the socket (file) until it is untagged */ CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n", @@ -2321,10 +2328,6 @@ static int ctrl_cmd_tag(const char *input) atomic_long_read(&el_socket->file->f_count)); return 0; -err_tag_unref_put: - BUG_ON(tag_ref_entry->num_sock_tags <= 0); - tag_ref_entry->num_sock_tags--; - free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry); err_put: CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->f_count=%ld\n", input, atomic_long_read(&el_socket->file->f_count) - 1); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8579482c4ff..46759a953df 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -310,8 +310,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, [NL80211_ATTR_PID] = { .type = NLA_U32 }, [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, - [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, - .len = WLAN_PMKID_LEN }, + [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN }, [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c7dac175965..7b7cb305dfb 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1273,11 +1273,14 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) { + u16 prev_family; int i; if (nr > XFRM_MAX_DEPTH) return -EINVAL; + prev_family = family; + for (i = 0; i < nr; i++) { /* We never validated the ut->family value, so many * applications simply leave it at zero. The check was @@ -1289,6 +1292,12 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) if (!ut[i].family) ut[i].family = family; + if ((ut[i].mode == XFRM_MODE_TRANSPORT) && + (ut[i].family != prev_family)) + return -EINVAL; + + prev_family = ut[i].family; + switch (ut[i].family) { case AF_INET: break; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7b596b5751d..a5c5fc3f019 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -108,6 +108,7 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) return -ENOMEM; runtime->substream = substream; spin_lock_init(&runtime->lock); + mutex_init(&runtime->realloc_mutex); init_waitqueue_head(&runtime->sleep); INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work); runtime->event = NULL; @@ -622,8 +623,10 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { char *newbuf; + char *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; - + unsigned long flags; + if (substream->append && substream->use_count > 1) return -EBUSY; snd_rawmidi_drain_output(substream); @@ -634,13 +637,22 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, + mutex_lock(&runtime->realloc_mutex); + newbuf = __krealloc(runtime->buffer, params->buffer_size, GFP_KERNEL); - if (!newbuf) + if (!newbuf) { + mutex_unlock(&runtime->realloc_mutex); return -ENOMEM; + } + spin_lock_irqsave(&runtime->lock, flags); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; runtime->avail = runtime->buffer_size; + spin_unlock_irqrestore(&runtime->lock, flags); + if (oldbuf != newbuf) + kfree(oldbuf); + mutex_unlock(&runtime->realloc_mutex); } runtime->avail_min = params->avail_min; substream->active_sensing = !params->no_active_sensing; @@ -651,7 +663,9 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, struct snd_rawmidi_params * params) { char *newbuf; + char *oldbuf; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; snd_rawmidi_drain_input(substream); if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { @@ -661,12 +675,21 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, return -EINVAL; } if (params->buffer_size != runtime->buffer_size) { - newbuf = krealloc(runtime->buffer, params->buffer_size, + mutex_lock(&runtime->realloc_mutex); + newbuf = __krealloc(runtime->buffer, params->buffer_size, GFP_KERNEL); - if (!newbuf) + if (!newbuf) { + mutex_unlock(&runtime->realloc_mutex); return -ENOMEM; + } + spin_lock_irqsave(&runtime->lock, flags); + oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; + spin_unlock_irqrestore(&runtime->lock, flags); + if (oldbuf != newbuf) + kfree(oldbuf); + mutex_unlock(&runtime->realloc_mutex); } runtime->avail_min = params->avail_min; return 0; @@ -935,6 +958,9 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; + spin_lock_irqsave(&runtime->lock, flags); + if (userbuf) + mutex_lock(&runtime->realloc_mutex); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) @@ -948,6 +974,7 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, runtime->buffer + runtime->appl_ptr, count1)) { + mutex_unlock(&runtime->realloc_mutex); return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); @@ -959,6 +986,9 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, result += count1; count -= count1; } + spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); return result; } @@ -1168,10 +1198,14 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, return -EINVAL; result = 0; + if (userbuf) + mutex_lock(&runtime->realloc_mutex); spin_lock_irqsave(&runtime->lock, flags); if (substream->append) { if ((long)runtime->avail < count) { spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); return -EAGAIN; } } @@ -1203,6 +1237,8 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, __end: count1 = runtime->avail < runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); + if (userbuf) + mutex_unlock(&runtime->realloc_mutex); if (count1) snd_rawmidi_output_trigger(substream, 1); return result; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 4dc6bae80e1..c73c8a5987c 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1245,6 +1245,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, struct snd_seq_client_port *port; struct snd_seq_port_info info; struct snd_seq_port_callback *callback; + int port_idx; if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; @@ -1258,7 +1259,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, return -ENOMEM; if (client->type == USER_CLIENT && info.kernel) { - snd_seq_delete_port(client, port->addr.port); + port_idx = port->addr.port; + snd_seq_port_unlock(port); + snd_seq_delete_port(client, port_idx); return -EINVAL; } if (client->type == KERNEL_CLIENT) { @@ -1280,6 +1283,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, snd_seq_set_port_info(port, &info); snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port); + snd_seq_port_unlock(port); if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 9516e5ce3aa..3de14e01d55 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp) } -/* create a port, port number is returned (-1 on failure) */ +/* create a port, port number is returned (-1 on failure); + * the caller needs to unref the port via snd_seq_port_unlock() appropriately + */ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port) { @@ -153,6 +155,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, snd_use_lock_init(&new_port->use_lock); port_subs_info_init(&new_port->c_src); port_subs_info_init(&new_port->c_dest); + snd_use_lock_use(&new_port->use_lock); num = port >= 0 ? port : 0; mutex_lock(&client->ports_mutex); @@ -167,9 +170,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, list_add_tail(&new_port->list, &p->list); client->num_ports++; new_port->addr.port = num; /* store the port number in the port */ + sprintf(new_port->name, "port-%d", num); write_unlock_irqrestore(&client->ports_lock, flags); mutex_unlock(&client->ports_mutex); - sprintf(new_port->name, "port-%d", num); return new_port; } diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 6ac4dd24e19..4ea1af0ef5a 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -144,6 +144,11 @@ static ssize_t audio_output_latency_dbgfs_read(struct file *file, pr_err("%s: out_buffer is null\n", __func__); return 0; } + if (count < OUT_BUFFER_SIZE) { + pr_err("%s: read size %d exceeds buf size %zd\n", __func__, + OUT_BUFFER_SIZE, count); + return 0; + } snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\ out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\ out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec); @@ -197,6 +202,11 @@ static ssize_t audio_input_latency_dbgfs_read(struct file *file, pr_err("%s: in_buffer is null\n", __func__); return 0; } + if (count < IN_BUFFER_SIZE) { + pr_err("%s: read size %d exceeds buf size %zd\n", __func__, + IN_BUFFER_SIZE, count); + return 0; + } snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\ in_cont_tv.tv_sec, in_cont_tv.tv_usec); return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos, diff --git a/sound/usb/card.c b/sound/usb/card.c index 36737a07806..d7742d6477d 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -595,6 +595,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, { struct snd_card *card; struct list_head *p, *n; + struct usb_mixer_interface *mixer; if (chip == (void *)-1L) return; @@ -622,7 +623,8 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, } /* release mixer resources */ list_for_each(p, &chip->mixer_list) { - snd_usb_mixer_disconnect(p); + mixer = list_entry(p, struct usb_mixer_interface, list); + snd_usb_mixer_disconnect(mixer); } usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 824cddf7521..f92c4a7a346 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2071,6 +2071,9 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) { + /* kill pending URBs */ + snd_usb_mixer_disconnect(mixer); + kfree(mixer->id_elems); if (mixer->urb) { kfree(mixer->urb->transfer_buffer); @@ -2412,11 +2415,13 @@ _error: return err; } -void snd_usb_mixer_disconnect(struct list_head *p) +void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer) { - struct usb_mixer_interface *mixer; - - mixer = list_entry(p, struct usb_mixer_interface, list); - usb_kill_urb(mixer->urb); - usb_kill_urb(mixer->rc_urb); + if (mixer->disconnected) + return; + if (mixer->urb) + usb_kill_urb(mixer->urb); + if (mixer->rc_urb) + usb_kill_urb(mixer->rc_urb); + mixer->disconnected = true; } diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index aab80df201b..500bc0660e7 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -23,6 +23,7 @@ struct usb_mixer_interface { u8 audigy2nx_leds[3]; u8 xonar_u1_status; + bool disconnected; }; #define MAX_CHANNELS 16 /* max logical channels */ @@ -57,7 +58,7 @@ struct usb_mixer_elem_info { int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error); -void snd_usb_mixer_disconnect(struct list_head *p); +void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer); void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); |