aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-07-25 17:00:26 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-07-25 17:00:26 +0000
commitd14e4d704776cca45d5675c3a86d356370760d1c (patch)
tree6db9b657c7935864f9a77d500d0b7dfa3b8e02fe
parentb01652073d38e223f6569cb254b773593cc28f51 (diff)
parent89354a04f75ef22117dffcd0e32a89b0d352b9a1 (diff)
downloadqcom-msm8x09-v3.10-d14e4d704776cca45d5675c3a86d356370760d1c.tar.gz
Snap for 4911710 from 89354a04f75ef22117dffcd0e32a89b0d352b9a1 to nyc-iot-release
Change-Id: I2347790546f48874df8f54f4d635ac2be4d5f13b
-rw-r--r--drivers/clocksource/Kconfig8
-rw-r--r--drivers/clocksource/arm_arch_timer.c8
-rw-r--r--drivers/hid/usbhid/hid-core.c12
-rw-r--r--drivers/platform/msm/ipa/ipa_rt.c11
-rw-r--r--drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_defrag.c8
-rw-r--r--drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_rx_reorder.c23
-rw-r--r--drivers/staging/qcacld-2.0/CORE/CLD_TXRX/TXRX/ol_tx_send.c16
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/inc/wlan_hdd_main.h15
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_cfg80211.c149
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_hostapd.c1
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_main.c439
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_p2p.c74
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.c202
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_request_manager.h220
-rw-r--r--drivers/staging/qcacld-2.0/CORE/HDD/src/wlan_hdd_wext.c1115
-rw-r--r--drivers/staging/qcacld-2.0/CORE/SERVICES/WMA/wma.c82
-rw-r--r--drivers/staging/qcacld-2.0/CORE/SERVICES/WMI/wmi_tlv_helper.c65
-rw-r--r--drivers/staging/qcacld-2.0/CORE/UTILS/FWLOG/dbglog_host.c13
-rw-r--r--drivers/staging/qcacld-2.0/CORE/UTILS/PKTLOG/linux_ac.c12
-rw-r--r--drivers/staging/qcacld-2.0/Kbuild1
-rw-r--r--drivers/usb/core/config.c20
-rw-r--r--drivers/usb/dwc3/dbm-1_4.c27
-rw-r--r--drivers/usb/dwc3/dbm-1_5.c27
-rwxr-xr-xdrivers/video/msm/mdss/mdp3_ctrl.c5
-rw-r--r--fs/dcache.c105
-rw-r--r--fs/debugfs/inode.c10
-rw-r--r--fs/namei.c8
-rw-r--r--fs/notify/fsnotify.c8
-rw-r--r--include/linux/dcache.h7
-rw-r--r--include/linux/fsnotify.h31
-rw-r--r--include/sound/rawmidi.h1
-rw-r--r--include/uapi/linux/usb/ch9.h1
-rw-r--r--net/netfilter/xt_qtaguid.c19
-rw-r--r--net/wireless/nl80211.c3
-rw-r--r--net/xfrm/xfrm_user.c9
-rw-r--r--sound/core/rawmidi.c46
-rw-r--r--sound/core/seq/seq_clientmgr.c6
-rw-r--r--sound/core/seq/seq_ports.c7
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c10
-rw-r--r--sound/usb/card.c4
-rw-r--r--sound/usb/mixer.c17
-rw-r--r--sound/usb/mixer.h3
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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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(&params);
+ 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 = &param_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 = &param_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(&register_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);